diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 261: CanvasGeneric: Replace custom Canvases with a customizable generic Canvas

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

Commit Message

alexandros.frantzis@linaro.org March 4, 2013, 7:06 p.m. UTC
Merge authors:
  Alexandros Frantzis (afrantzis)
Related merge proposals:
  https://code.launchpad.net/~glmark2-dev/glmark2/canvas-generic/+merge/151271
  proposed by: Alexandros Frantzis (afrantzis)
  review: Approve - Jesse Barker (jesse-barker)
------------------------------------------------------------
revno: 261 [merge]
committer: Alexandros Frantzis <alexandros.frantzis@canonical.com>
branch nick: trunk
timestamp: Mon 2013-03-04 21:02:58 +0200
message:
  CanvasGeneric: Replace custom Canvases with a customizable generic Canvas
  
  The generic Canvas is customized by initializing it with a NativeState
  (X11,DRM...) and a GLState (EGL,GLX). This separation of concerns makes
  it easier to support new display systems.
removed:
  src/canvas-drm.cpp
  src/canvas-drm.h
  src/canvas-x11-egl.cpp
  src/canvas-x11.cpp
  src/canvas-x11.h
added:
  src/canvas-generic.cpp
  src/canvas-generic.h
  src/gl-state.h
  src/native-state-drm.cpp
  src/native-state-drm.h
  src/native-state-x11.cpp
  src/native-state.h
renamed:
  src/canvas-x11-egl.h => src/native-state-x11.h
  src/canvas-x11-glx.cpp => src/gl-state-glx.cpp
  src/canvas-x11-glx.h => src/gl-state-glx.h
  src/egl-state.cpp => src/gl-state-egl.cpp
  src/egl-state.h => src/gl-state-egl.h
modified:
  android/jni/Android.mk
  android/jni/Android.ndk.mk
  src/main.cpp
  src/wscript_build
  src/native-state-x11.h
  src/gl-state-glx.cpp
  src/gl-state-glx.h
  src/gl-state-egl.cpp
  src/gl-state-egl.h


--
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 'android/jni/Android.mk'
--- android/jni/Android.mk	2012-12-18 19:44:34 +0000
+++ android/jni/Android.mk	2013-03-01 15:22:03 +0000
@@ -65,7 +65,7 @@ 
                     $(LOCAL_PATH)/src/libjpeg-turbo \
                     $(LOCAL_PATH)/src/libpng \
                     external/zlib
-LOCAL_SRC_FILES := $(filter-out src/canvas% src/main.cpp, \
+LOCAL_SRC_FILES := $(filter-out src/canvas% src/gl-state% src/native-state% src/main.cpp, \
                      $(subst $(LOCAL_PATH)/,,$(wildcard $(LOCAL_PATH)/src/*.cpp))) \
                    $(subst $(LOCAL_PATH)/,,$(wildcard $(LOCAL_PATH)/src/scene-terrain/*.cpp)) \
                    src/canvas-android.cpp

=== modified file 'android/jni/Android.ndk.mk'
--- android/jni/Android.ndk.mk	2012-12-18 19:44:34 +0000
+++ android/jni/Android.ndk.mk	2013-03-01 15:22:03 +0000
@@ -57,7 +57,7 @@ 
                     $(LOCAL_PATH)/src/scene-terrain \
                     $(LOCAL_PATH)/src/libjpeg-turbo \
                     $(LOCAL_PATH)/src/libpng
-LOCAL_SRC_FILES := $(filter-out src/canvas% src/main.cpp, \
+LOCAL_SRC_FILES := $(filter-out src/canvas% src/gl-state% src/native-state% src/main.cpp, \
                      $(subst $(LOCAL_PATH)/,,$(wildcard $(LOCAL_PATH)/src/*.cpp))) \
                    $(subst $(LOCAL_PATH)/,,$(wildcard $(LOCAL_PATH)/src/scene-terrain/*.cpp)) \
                    src/canvas-android.cpp

=== removed file 'src/canvas-drm.cpp'
--- src/canvas-drm.cpp	2012-12-17 22:48:52 +0000
+++ src/canvas-drm.cpp	1970-01-01 00:00:00 +0000
@@ -1,587 +0,0 @@ 
-//
-// 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);
-}

=== removed file 'src/canvas-drm.h'
--- src/canvas-drm.h	2012-12-17 19:11:54 +0000
+++ src/canvas-drm.h	1970-01-01 00:00:00 +0000
@@ -1,132 +0,0 @@ 
-//
-// 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

=== added file 'src/canvas-generic.cpp'
--- src/canvas-generic.cpp	1970-01-01 00:00:00 +0000
+++ src/canvas-generic.cpp	2013-03-01 14:48:21 +0000
@@ -0,0 +1,442 @@ 
+/*
+ * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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:
+ *  Alexandros Frantzis
+ */
+#include "canvas-generic.h"
+#include "native-state.h"
+#include "gl-state.h"
+#include "log.h"
+#include "options.h"
+#include "util.h"
+
+#include <fstream>
+#include <sstream>
+
+/******************
+ * Public methods *
+ ******************/
+
+bool
+CanvasGeneric::init()
+{
+    if (!native_state_.init_display())
+        return false;
+
+    gl_state_.init_display(native_state_.display(), visual_config_);
+
+    return reset();
+}
+
+bool
+CanvasGeneric::reset()
+{
+    release_fbo();
+
+    if (!gl_state_.reset())
+        return false;
+
+    if (!resize_no_viewport(width_, height_))
+        return false;
+
+    if (!do_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();
+
+    return true;
+}
+
+void
+CanvasGeneric::visible(bool visible)
+{
+    if (visible && !offscreen_)
+        native_state_.visible(visible);
+}
+
+void
+CanvasGeneric::clear()
+{
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+#if USE_GL
+    glClearDepth(1.0f);
+#elif USE_GLESv2
+    glClearDepthf(1.0f);
+#endif
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void
+CanvasGeneric::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:
+            gl_state_.swap();
+            native_state_.flip();
+            break;
+        case Options::FrameEndFinish:
+            glFinish();
+            break;
+        case Options::FrameEndReadPixels:
+            read_pixel(width_ / 2, height_ / 2);
+            break;
+        case Options::FrameEndNone:
+        default:
+            break;
+    }
+}
+
+void
+CanvasGeneric::print_info()
+{
+    do_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
+CanvasGeneric::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
+CanvasGeneric::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
+CanvasGeneric::should_quit()
+{
+    return native_state_.should_quit();
+}
+
+void
+CanvasGeneric::resize(int width, int height)
+{
+    resize_no_viewport(width, height);
+    glViewport(0, 0, width_, height_);
+}
+
+unsigned int
+CanvasGeneric::fbo()
+{
+    return fbo_;
+}
+
+
+/*******************
+ * Private methods *
+ *******************/
+
+bool
+CanvasGeneric::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
+CanvasGeneric::resize_no_viewport(int width, int height)
+{
+    bool request_fullscreen = (width == -1 && height == -1);
+
+    int vid;
+    if (!gl_state_.gotNativeConfig(vid))
+    {
+        Log::error("Error: Couldn't get GL visual config!\n");
+        return false;
+    }
+
+    NativeState::WindowProperties properties(width, height,
+                                             request_fullscreen, vid);
+    NativeState::WindowProperties cur_properties;
+
+    native_state_.window(cur_properties);
+
+    if ((cur_properties.fullscreen == properties.fullscreen &&
+         cur_properties.width > 0 && cur_properties.height > 0) ||
+        (cur_properties.width == properties.width &&
+         cur_properties.height == properties.height))
+    {
+        return true;
+    }
+
+    if (!native_state_.create_window(properties))
+    {
+        Log::error("Error: Couldn't create native window!\n");
+        return false;
+    }
+
+    native_window_ = native_state_.window(cur_properties);
+
+    width_ = cur_properties.width;
+    height_ = cur_properties.height;
+
+    if (color_renderbuffer_) {
+        glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_);
+        glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_,
+                              width_, height_);
+    }
+
+    if (depth_renderbuffer_) {
+        glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_);
+        glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_,
+                              width_, height_);
+    }
+
+    projection_ = LibMatrix::Mat4::perspective(60.0, width_ / static_cast<float>(height_),
+                                               1.0, 1024.0);
+
+    return true;
+}
+
+bool
+CanvasGeneric::do_make_current()
+{
+    gl_state_.init_surface(native_window_);
+
+    if (!gl_state_.valid()) {
+        Log::error("CanvasGeneric: Invalid EGL state\n");
+        return false;
+    }
+
+    gl_state_.init_gl_extensions();
+
+    if (offscreen_) {
+        if (!ensure_fbo())
+            return false;
+
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
+    }
+
+    return true;
+}
+
+bool
+CanvasGeneric::ensure_gl_formats()
+{
+    if (gl_color_format_ && gl_depth_format_)
+        return true;
+
+    GLVisualConfig vc;
+    gl_state_.getVisualConfig(vc);
+
+    gl_color_format_ = 0;
+    gl_depth_format_ = 0;
+
+    bool supports_rgba8(false);
+    bool supports_rgb8(false);
+    bool supports_depth24(false);
+    bool supports_depth32(false);
+
+#if USE_GLESv2
+    if (GLExtensions::support("GL_ARM_rgba8"))
+        supports_rgba8 = true;
+
+    if (GLExtensions::support("GL_OES_rgb8_rgba8")) {
+        supports_rgba8 = true;
+        supports_rgb8 = true;
+    }
+
+    if (GLExtensions::support("GL_OES_depth24"))
+        supports_depth24 = true;
+
+    if (GLExtensions::support("GL_OES_depth32"))
+        supports_depth32 = true;
+#elif USE_GL
+    supports_rgba8 = true;
+    supports_rgb8 = true;
+    supports_depth24 = true;
+    supports_depth32 = true;
+#endif
+
+    if (vc.buffer == 32) {
+        if (supports_rgba8)
+            gl_color_format_ = GL_RGBA8;
+        else
+            gl_color_format_ = GL_RGBA4;
+    }
+    else if (vc.buffer == 24) {
+        if (supports_rgb8)
+            gl_color_format_ = GL_RGB8;
+        else
+            gl_color_format_ = GL_RGB565;
+    }
+    else if (vc.buffer == 16) {
+        if (vc.red == 4 && vc.green == 4 &&
+            vc.blue == 4 && vc.alpha == 4)
+        {
+            gl_color_format_ = GL_RGBA4;
+        }
+        else if (vc.red == 5 && vc.green == 5 &&
+                 vc.blue == 5 && vc.alpha == 1)
+        {
+            gl_color_format_ = GL_RGB5_A1;
+        }
+        else if (vc.red == 5 && vc.green == 6 &&
+                 vc.blue == 5 && vc.alpha == 0)
+        {
+            gl_color_format_ = GL_RGB565;
+        }
+    }
+
+    if (vc.depth == 32 && supports_depth32)
+        gl_depth_format_ = GL_DEPTH_COMPONENT32;
+    else if (vc.depth >= 24 && supports_depth24)
+        gl_depth_format_ = GL_DEPTH_COMPONENT24;
+    else if (vc.depth == 16)
+        gl_depth_format_ = GL_DEPTH_COMPONENT16;
+
+    Log::debug("Selected Renderbuffer ColorFormat: %s DepthFormat: %s\n",
+               get_gl_format_str(gl_color_format_),
+               get_gl_format_str(gl_depth_format_));
+
+    return (gl_color_format_ && gl_depth_format_);
+}
+
+bool
+CanvasGeneric::ensure_fbo()
+{
+    if (!fbo_) {
+        if (!ensure_gl_formats())
+            return false;
+
+        /* Create a texture for the color attachment  */
+        glGenRenderbuffers(1, &color_renderbuffer_);
+        glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_);
+        glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_,
+                              width_, height_);
+
+        /* Create a renderbuffer for the depth attachment */
+        glGenRenderbuffers(1, &depth_renderbuffer_);
+        glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_);
+        glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_,
+                              width_, height_);
+
+        /* Create a FBO and set it up */
+        glGenFramebuffers(1, &fbo_);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                  GL_RENDERBUFFER, color_renderbuffer_);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                  GL_RENDERBUFFER, depth_renderbuffer_);
+    }
+
+    return true;
+}
+
+void
+CanvasGeneric::release_fbo()
+{
+    glDeleteFramebuffers(1, &fbo_);
+    glDeleteRenderbuffers(1, &color_renderbuffer_);
+    glDeleteRenderbuffers(1, &depth_renderbuffer_);
+    fbo_ = 0;
+    color_renderbuffer_ = 0;
+    depth_renderbuffer_ = 0;
+
+    gl_color_format_ = 0;
+    gl_depth_format_ = 0;
+}
+
+const char *
+CanvasGeneric::get_gl_format_str(GLenum f)
+{
+    const char *str;
+
+    switch(f) {
+        case GL_RGBA8: str = "GL_RGBA8"; break;
+        case GL_RGB8: str = "GL_RGB8"; break;
+        case GL_RGBA4: str = "GL_RGBA4"; break;
+        case GL_RGB5_A1: str = "GL_RGB5_A1"; break;
+        case GL_RGB565: str = "GL_RGB565"; break;
+        case GL_DEPTH_COMPONENT16: str = "GL_DEPTH_COMPONENT16"; break;
+        case GL_DEPTH_COMPONENT24: str = "GL_DEPTH_COMPONENT24"; break;
+        case GL_DEPTH_COMPONENT32: str = "GL_DEPTH_COMPONENT32"; break;
+        case GL_NONE: str = "GL_NONE"; break;
+        default: str = "Unknown"; break;
+    }
+
+    return str;
+}

=== added file 'src/canvas-generic.h'
--- src/canvas-generic.h	1970-01-01 00:00:00 +0000
+++ src/canvas-generic.h	2013-03-01 14:48:21 +0000
@@ -0,0 +1,75 @@ 
+/*
+ * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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:
+ *  Alexandros Frantzis
+ */
+#ifndef GLMARK2_CANVAS_GENERIC_H_
+#define GLMARK2_CANVAS_GENERIC_H_
+
+#include "canvas.h"
+
+class GLState;
+class NativeState;
+
+/**
+ * Canvas for rendering with GL to an X11 window.
+ */
+class CanvasGeneric : public Canvas
+{
+public:
+    CanvasGeneric(NativeState& native_state, GLState& gl_state,
+                  int width, int height)
+        : Canvas(width, height),
+          native_state_(native_state), gl_state_(gl_state),
+          gl_color_format_(0), gl_depth_format_(0),
+          color_renderbuffer_(0), depth_renderbuffer_(0), fbo_(0) {}
+
+    bool init();
+    bool reset();
+    void visible(bool visible);
+    void clear();
+    void update();
+    void print_info();
+    Pixel read_pixel(int x, int y);
+    void write_to_file(std::string &filename);
+    bool should_quit();
+    void resize(int width, int height);
+    unsigned int fbo();
+
+private:
+    bool supports_gl2();
+    bool resize_no_viewport(int width, int height);
+    bool do_make_current();
+    bool ensure_gl_formats();
+    bool ensure_fbo();
+    void release_fbo();
+    const char *get_gl_format_str(GLenum f);
+
+    NativeState& native_state_;
+    GLState& gl_state_;
+    void* native_window_;
+    GLenum gl_color_format_;
+    GLenum gl_depth_format_;
+    GLuint color_renderbuffer_;
+    GLuint depth_renderbuffer_;
+    GLuint fbo_;
+};
+
+#endif /* GLMARK2_CANVAS_GENERIC_H_ */

=== removed file 'src/canvas-x11-egl.cpp'
--- src/canvas-x11-egl.cpp	2012-12-12 19:45:49 +0000
+++ src/canvas-x11-egl.cpp	1970-01-01 00:00:00 +0000
@@ -1,117 +0,0 @@ 
-/*
- * Copyright Š 2010-2011 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:
- *  Alexandros Frantzis (glmark2)
- */
-#include "canvas-x11-egl.h"
-#include "log.h"
-#include "options.h"
-
-#include <fstream>
-#include <sstream>
-#include <climits>
-
-/*********************
- * Protected methods *
- *********************/
-
-bool
-CanvasX11EGL::init_gl_winsys()
-{
-    egl_.init_display(xdpy_, visual_config_);
-    return true;
-}
-
-XVisualInfo *
-CanvasX11EGL::get_xvisualinfo()
-{
-    XVisualInfo vis_tmpl;
-    XVisualInfo *vis_info;
-    int num_visuals;
-    EGLint vid;
-
-    if (!egl_.gotNativeConfig(vid))
-    {
-        Log::error("Failed to get a native-renderable EGLConfig\n");
-        return 0;
-    }
-
-    /* The X window visual must match the EGL config */
-    vis_tmpl.visualid = vid;
-    vis_info = XGetVisualInfo(xdpy_, VisualIDMask, &vis_tmpl,
-                             &num_visuals);
-    if (!vis_info) {
-        Log::error("couldn't get X visual\n");
-        return 0;
-    }
-
-    return vis_info;
-}
-
-bool
-CanvasX11EGL::make_current()
-{
-    egl_.init_surface(xwin_);
-    if (!egl_.valid()) {
-        Log::error("CanvasX11EGL: Invalid EGL state\n");
-        return false;
-    }
-
-    init_gl_extensions();
-
-    return true;
-}
-
-void
-CanvasX11EGL::swap_buffers()
-{
-    egl_.swap();
-}
-
-void
-CanvasX11EGL::get_glvisualconfig(GLVisualConfig &visual_config)
-{
-    egl_.getVisualConfig(visual_config);
-}
-
-/*******************
- * Private methods *
- *******************/
-
-bool
-CanvasX11EGL::reset_context()
-{
-    return egl_.reset();
-}
-
-void
-CanvasX11EGL::init_gl_extensions()
-{
-#if USE_GLESv2
-    if (GLExtensions::support("GL_OES_mapbuffer")) {
-        GLExtensions::MapBuffer =
-            reinterpret_cast<PFNGLMAPBUFFEROESPROC>(eglGetProcAddress("glMapBufferOES"));
-        GLExtensions::UnmapBuffer =
-            reinterpret_cast<PFNGLUNMAPBUFFEROESPROC>(eglGetProcAddress("glUnmapBufferOES"));
-    }
-#elif USE_GL
-    GLExtensions::MapBuffer = glMapBuffer;
-    GLExtensions::UnmapBuffer = glUnmapBuffer;
-#endif
-}

=== removed file 'src/canvas-x11.cpp'
--- src/canvas-x11.cpp	2012-11-13 16:56:32 +0000
+++ src/canvas-x11.cpp	1970-01-01 00:00:00 +0000
@@ -1,526 +0,0 @@ 
-/*
- * Copyright Š 2010-2011 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:
- *  Alexandros Frantzis (glmark2)
- *  Jesse Barker
- */
-#include "canvas-x11.h"
-#include "log.h"
-#include "options.h"
-#include "util.h"
-
-#include <X11/keysym.h>
-#include <X11/Xatom.h>
-#include <fstream>
-#include <sstream>
-
-/******************
- * Public methods *
- ******************/
-bool
-CanvasX11::reset()
-{
-    release_fbo();
-
-    if (!reset_context())
-        return false;
-
-    if (!do_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();
-
-    return true;
-}
-
-bool
-CanvasX11::init()
-{
-    xdpy_ = XOpenDisplay(NULL);
-    if (!xdpy_)
-        return false;
-
-    if (!init_gl_winsys())
-        return false;
-
-    resize_no_viewport(width_, height_);
-
-    if (!xwin_)
-        return false;
-
-    return reset();
-}
-
-void
-CanvasX11::visible(bool visible)
-{
-    if (visible && !offscreen_)
-        XMapWindow(xdpy_, xwin_);
-}
-
-void
-CanvasX11::clear()
-{
-    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-#if USE_GL
-    glClearDepth(1.0f);
-#elif USE_GLESv2
-    glClearDepthf(1.0f);
-#endif
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-}
-
-void
-CanvasX11::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
-CanvasX11::print_info()
-{
-    do_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
-CanvasX11::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
-CanvasX11::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
-CanvasX11::should_quit()
-{
-    XEvent event;
-
-    if (!XPending(xdpy_))
-        return false;
-
-    XNextEvent(xdpy_, &event);
-
-    if (event.type == KeyPress) {
-        if (XLookupKeysym(&event.xkey, 0) == XK_Escape)
-            return true;
-    }
-    else if (event.type == ClientMessage) {
-        /* Window Delete event from window manager */
-        return true;
-    }
-
-    return false;
-}
-
-void
-CanvasX11::resize(int width, int height)
-{
-    resize_no_viewport(width, height);
-    glViewport(0, 0, width_, height_);
-}
-
-unsigned int
-CanvasX11::fbo()
-{
-    return fbo_;
-}
-
-bool
-CanvasX11::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;
-}
-
-/*******************
- * Private methods *
- *******************/
-
-bool
-CanvasX11::ensure_x_window()
-{
-    static const char *win_name("glmark2 "GLMARK_VERSION);
-
-    if (xwin_)
-        return true;
-
-    if (!xdpy_) {
-        Log::error("Error: X11 Display has not been initialized!\n");
-        return false;
-    }
-
-    XVisualInfo *vis_info = get_xvisualinfo();
-    if (!vis_info) {
-        Log::error("Error: Could not get a valid XVisualInfo!\n");
-        return false;
-    }
-
-    Log::debug("Creating XWindow W: %d H: %d VisualID: 0x%x\n",
-               width_, height_, vis_info->visualid);
-
-    /* window attributes */
-    XSetWindowAttributes attr;
-    unsigned long mask;
-    Window root = RootWindow(xdpy_, DefaultScreen(xdpy_));
-
-    attr.background_pixel = 0;
-    attr.border_pixel = 0;
-    attr.colormap = XCreateColormap(xdpy_, root, vis_info->visual, AllocNone);
-    attr.event_mask = KeyPressMask;
-    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
-
-    xwin_ = XCreateWindow(xdpy_, root, 0, 0, width_, height_,
-                          0, vis_info->depth, InputOutput,
-                          vis_info->visual, mask, &attr);
-
-    XFree(vis_info);
-
-    if (!xwin_) {
-        Log::error("Error: XCreateWindow() failed!\n");
-        return false;
-    }
-
-    /* set hints and properties */
-    if (fullscreen_) {
-        Atom atom = XInternAtom(xdpy_, "_NET_WM_STATE_FULLSCREEN", True);
-        XChangeProperty(xdpy_, xwin_,
-                        XInternAtom(xdpy_, "_NET_WM_STATE", True),
-                        XA_ATOM, 32, PropModeReplace,
-                        reinterpret_cast<unsigned char*>(&atom),  1);
-    }
-    else {
-        XSizeHints sizehints;
-        sizehints.min_width  = width_;
-        sizehints.min_height = height_;
-        sizehints.max_width  = width_;
-        sizehints.max_height = height_;
-        sizehints.flags = PMaxSize | PMinSize;
-
-        XSetWMProperties(xdpy_, xwin_, NULL, NULL,
-                         NULL, 0, &sizehints, NULL, NULL);
-    }
-
-    /* Set the window name */
-    XStoreName(xdpy_ , xwin_,  win_name);
-
-    /* Gracefully handle Window Delete event from window manager */
-    Atom wmDelete = XInternAtom(xdpy_, "WM_DELETE_WINDOW", True);
-    XSetWMProtocols(xdpy_, xwin_, &wmDelete, 1);
-
-    return true;
-}
-
-void
-CanvasX11::resize_no_viewport(int width, int height)
-{
-    bool request_fullscreen = (width == -1 || height == -1);
-
-    /* Recreate an existing window only if it has actually been resized */
-    if (xwin_) {
-        if (width_ != width || height_ != height ||
-            fullscreen_ != request_fullscreen)
-        {
-            XDestroyWindow(xdpy_, xwin_);
-            xwin_ = 0;
-        }
-        else
-        {
-            return;
-        }
-    }
-
-    fullscreen_ = request_fullscreen;
-
-    if (fullscreen_) {
-        /* Get the screen (root window) size */
-        XWindowAttributes window_attr;
-        XGetWindowAttributes(xdpy_, RootWindow(xdpy_, DefaultScreen(xdpy_)), 
-                             &window_attr);
-        width_ = window_attr.width;
-        height_ = window_attr.height;
-    }
-    else {
-        width_ = width;
-        height_ = height;
-    }
-
-    if (!ensure_x_window())
-        Log::error("Error: Couldn't create X Window!\n");
-
-    if (color_renderbuffer_) {
-        glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_);
-        glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_,
-                              width_, height_);
-    }
-
-    if (depth_renderbuffer_) {
-        glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_);
-        glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_,
-                              width_, height_);
-    }
-
-    projection_ = LibMatrix::Mat4::perspective(60.0, width_ / static_cast<float>(height_),
-                                               1.0, 1024.0);
-}
-
-bool
-CanvasX11::do_make_current()
-{
-    if (!make_current())
-        return false;
-
-    if (offscreen_) {
-        if (!ensure_fbo())
-            return false;
-
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
-    }
-
-    return true;
-}
-
-bool
-CanvasX11::ensure_gl_formats()
-{
-    if (gl_color_format_ && gl_depth_format_)
-        return true;
-
-    GLVisualConfig vc;
-    get_glvisualconfig(vc);
-
-    gl_color_format_ = 0;
-    gl_depth_format_ = 0;
-
-    bool supports_rgba8(false);
-    bool supports_rgb8(false);
-    bool supports_depth24(false);
-    bool supports_depth32(false);
-
-#if USE_GLESv2
-    if (GLExtensions::support("GL_ARM_rgba8"))
-        supports_rgba8 = true;
-
-    if (GLExtensions::support("GL_OES_rgb8_rgba8")) {
-        supports_rgba8 = true;
-        supports_rgb8 = true;
-    }
-
-    if (GLExtensions::support("GL_OES_depth24"))
-        supports_depth24 = true;
-
-    if (GLExtensions::support("GL_OES_depth32"))
-        supports_depth32 = true;
-#elif USE_GL
-    supports_rgba8 = true;
-    supports_rgb8 = true;
-    supports_depth24 = true;
-    supports_depth32 = true;
-#endif
-
-    if (vc.buffer == 32) {
-        if (supports_rgba8)
-            gl_color_format_ = GL_RGBA8;
-        else
-            gl_color_format_ = GL_RGBA4;
-    }
-    else if (vc.buffer == 24) {
-        if (supports_rgb8)
-            gl_color_format_ = GL_RGB8;
-        else
-            gl_color_format_ = GL_RGB565;
-    }
-    else if (vc.buffer == 16) {
-        if (vc.red == 4 && vc.green == 4 &&
-            vc.blue == 4 && vc.alpha == 4)
-        {
-            gl_color_format_ = GL_RGBA4;
-        }
-        else if (vc.red == 5 && vc.green == 5 &&
-                 vc.blue == 5 && vc.alpha == 1)
-        {
-            gl_color_format_ = GL_RGB5_A1;
-        }
-        else if (vc.red == 5 && vc.green == 6 &&
-                 vc.blue == 5 && vc.alpha == 0)
-        {
-            gl_color_format_ = GL_RGB565;
-        }
-    }
-
-    if (vc.depth == 32 && supports_depth32)
-        gl_depth_format_ = GL_DEPTH_COMPONENT32;
-    else if (vc.depth >= 24 && supports_depth24)
-        gl_depth_format_ = GL_DEPTH_COMPONENT24;
-    else if (vc.depth == 16)
-        gl_depth_format_ = GL_DEPTH_COMPONENT16;
-
-    Log::debug("Selected Renderbuffer ColorFormat: %s DepthFormat: %s\n",
-               get_gl_format_str(gl_color_format_),
-               get_gl_format_str(gl_depth_format_));
-
-    return (gl_color_format_ && gl_depth_format_);
-}
-
-bool
-CanvasX11::ensure_fbo()
-{
-    if (!fbo_) {
-        if (!ensure_gl_formats())
-            return false;
-
-        /* Create a texture for the color attachment  */
-        glGenRenderbuffers(1, &color_renderbuffer_);
-        glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_);
-        glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_,
-                              width_, height_);
-
-        /* Create a renderbuffer for the depth attachment */
-        glGenRenderbuffers(1, &depth_renderbuffer_);
-        glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_);
-        glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_,
-                              width_, height_);
-
-        /* Create a FBO and set it up */
-        glGenFramebuffers(1, &fbo_);
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
-        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                  GL_RENDERBUFFER, color_renderbuffer_);
-        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                  GL_RENDERBUFFER, depth_renderbuffer_);
-    }
-
-    return true;
-}
-
-void
-CanvasX11::release_fbo()
-{
-    glDeleteFramebuffers(1, &fbo_);
-    glDeleteRenderbuffers(1, &color_renderbuffer_);
-    glDeleteRenderbuffers(1, &depth_renderbuffer_);
-    fbo_ = 0;
-    color_renderbuffer_ = 0;
-    depth_renderbuffer_ = 0;
-
-    gl_color_format_ = 0;
-    gl_depth_format_ = 0;
-}
-
-const char *
-CanvasX11::get_gl_format_str(GLenum f)
-{
-    const char *str;
-
-    switch(f) {
-        case GL_RGBA8: str = "GL_RGBA8"; break;
-        case GL_RGB8: str = "GL_RGB8"; break;
-        case GL_RGBA4: str = "GL_RGBA4"; break;
-        case GL_RGB5_A1: str = "GL_RGB5_A1"; break;
-        case GL_RGB565: str = "GL_RGB565"; break;
-        case GL_DEPTH_COMPONENT16: str = "GL_DEPTH_COMPONENT16"; break;
-        case GL_DEPTH_COMPONENT24: str = "GL_DEPTH_COMPONENT24"; break;
-        case GL_DEPTH_COMPONENT32: str = "GL_DEPTH_COMPONENT32"; break;
-        case GL_NONE: str = "GL_NONE"; break;
-        default: str = "Unknown"; break;
-    }
-
-    return str;
-}
-

=== removed file 'src/canvas-x11.h'
--- src/canvas-x11.h	2012-11-13 16:56:32 +0000
+++ src/canvas-x11.h	1970-01-01 00:00:00 +0000
@@ -1,141 +0,0 @@ 
-/*
- * Copyright Š 2010-2011 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:
- *  Alexandros Frantzis (glmark2)
- */
-#ifndef GLMARK2_CANVAS_X11_H_
-#define GLMARK2_CANVAS_X11_H_
-
-#include "canvas.h"
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-/**
- * Canvas for rendering with GL to an X11 window.
- */
-class CanvasX11 : public Canvas
-{
-public:
-    ~CanvasX11() {}
-
-    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);
-    virtual unsigned int fbo();
-
-protected:
-    CanvasX11(int width, int height) :
-        Canvas(width, height), xwin_(0), xdpy_(0), fullscreen_(false),
-        gl_color_format_(0), gl_depth_format_(0),
-        color_renderbuffer_(0), depth_renderbuffer_(0), fbo_(0) {}
-
-    /**
-     * Gets the XVisualInfo to use for creating the X window with.
-     *
-     * The caller should XFree() the returned XVisualInfo when done.
-     *
-     * This method should be implemented in derived classes.
-     *
-     * @return the XVisualInfo
-     */
-    virtual XVisualInfo *get_xvisualinfo() = 0;
-
-    /**
-     * Initializes window system interfaces for GL rendering.
-     *
-     * This method should be implemented in derived classes.
-     *
-     * @return whether the operation succeeded
-     */
-    virtual bool init_gl_winsys() = 0;
-
-    /**
-     * Makes the canvas the current target for GL rendering.
-     *
-     * This method should be implemented in derived classes.
-     *
-     * @return whether the operation succeeded
-     */
-    virtual bool make_current() = 0;
-
-    /**
-     * Resets the underlying GL context for rendering.
-     *
-     * This method should be implemented in derived classes.
-     *
-     * @return whether the operation succeeded
-     */
-    virtual bool reset_context() = 0;
-
-    /**
-     * Swaps the GL buffers (assuming double buffering is used).
-     *
-     * This method should be implemented in derived classes.
-     *
-     * @return whether the operation succeeded
-     */
-    virtual void swap_buffers() = 0;
-
-    /**
-     * Gets information about the GL visual used for this canvas.
-     *
-     * This method should be implemented in derived classes.
-     */
-    virtual void get_glvisualconfig(GLVisualConfig &visual_config) = 0;
-
-    /**
-     * Whether the current implementation supports GL(ES) 2.0.
-     *
-     * @return true if it supports GL(ES) 2.0, false otherwise
-     */
-    bool supports_gl2();
-
-
-    /** The X window associated with this canvas. */
-    Window xwin_;
-    /** The X display associated with this canvas. */
-    Display *xdpy_;
-
-private:
-    void resize_no_viewport(int width, int height);
-    bool ensure_x_window();
-    bool do_make_current();
-    bool ensure_gl_formats();
-    bool ensure_fbo();
-    void release_fbo();
-
-    const char *get_gl_format_str(GLenum f);
-
-    bool fullscreen_;
-    GLenum gl_color_format_;
-    GLenum gl_depth_format_;
-    GLuint color_renderbuffer_;
-    GLuint depth_renderbuffer_;
-    GLuint fbo_;
-};
-
-#endif
-

=== renamed file 'src/egl-state.cpp' => 'src/gl-state-egl.cpp'
--- src/egl-state.cpp	2012-12-05 23:50:25 +0000
+++ src/gl-state-egl.cpp	2013-03-03 10:18:39 +0000
@@ -19,16 +19,22 @@ 
 // Authors:
 //  Jesse Barker
 //
-#include "egl-state.h"
+#include "gl-state-egl.h"
 #include "log.h"
 #include "options.h"
+#include "gl-headers.h"
 #include "limits.h"
+#include "gl-headers.h"
 #include <iomanip>
 #include <sstream>
 
 using std::vector;
 using std::string;
 
+/****************************
+ * EGLConfig public methods *
+ ****************************/
+
 EglConfig::EglConfig(EGLDisplay dpy, EGLConfig config) :
     handle_(config),
     bufferSize_(0),
@@ -185,8 +191,8 @@ 
         if (!eglGetConfigAttrib(dpy, handle_, EGL_SAMPLES, &samples_))
         {
             badAttribVec.push_back("EGL_SAMPLES");
-        }        
-    }    
+        }
+    }
     if (!eglGetConfigAttrib(dpy, handle_, EGL_TRANSPARENT_TYPE, &xparentType_))
     {
         badAttribVec.push_back("EGL_TRANSPARENT_TYPE");
@@ -277,18 +283,21 @@ 
     Log::debug("%s\n", s.str().c_str());
 }
 
+/*****************************
+ * GLStateEGL public methods *
+ ****************************/
 
 bool
-EGLState::init_display(EGLNativeDisplayType native_display, GLVisualConfig& visual_config)
+GLStateEGL::init_display(void* native_display, GLVisualConfig& visual_config)
 {
-    native_display_ = native_display;
-    visual_config_ = visual_config;
+    native_display_ = reinterpret_cast<EGLNativeDisplayType>(native_display);
+    requested_visual_config_ = visual_config;
 
     return gotValidDisplay();
 }
 
 bool
-EGLState::init_surface(EGLNativeWindowType native_window)
+GLStateEGL::init_surface(void* native_window)
 {
     native_window_ = reinterpret_cast<EGLNativeWindowType>(native_window);
 
@@ -296,13 +305,112 @@ 
 }
 
 void
-EGLState::swap()
+GLStateEGL::init_gl_extensions()
+{
+#if USE_GLESv2
+    if (GLExtensions::support("GL_OES_mapbuffer")) {
+        GLExtensions::MapBuffer =
+            reinterpret_cast<PFNGLMAPBUFFEROESPROC>(eglGetProcAddress("glMapBufferOES"));
+        GLExtensions::UnmapBuffer =
+            reinterpret_cast<PFNGLUNMAPBUFFEROESPROC>(eglGetProcAddress("glUnmapBufferOES"));
+    }
+#elif USE_GL
+    GLExtensions::MapBuffer = glMapBuffer;
+    GLExtensions::UnmapBuffer = glUnmapBuffer;
+#endif
+}
+
+bool
+GLStateEGL::valid()
+{
+    if (!gotValidDisplay())
+        return false;
+
+    if (!gotValidConfig())
+        return false;
+
+    if (!gotValidSurface())
+        return false;
+
+    if (!gotValidContext())
+        return false;
+
+    if (egl_context_ == eglGetCurrentContext())
+        return true;
+
+    if (!eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_)) {
+        Log::error("eglMakeCurrent failed with error: 0x%x\n", eglGetError());
+        return false;
+    }
+
+    if (!eglSwapInterval(egl_display_, 0)) {
+        Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n");
+    }
+
+    init_gl_extensions();
+
+    return true;
+}
+
+bool
+GLStateEGL::reset()
+{
+    if (!gotValidDisplay()) {
+        return false;
+    }
+
+    if (!egl_context_) {
+        return true;
+    }
+
+    if (EGL_FALSE == eglDestroyContext(egl_display_, egl_context_)) {
+        Log::debug("eglDestroyContext failed with error: 0x%x\n", eglGetError());
+    }
+
+    egl_context_ = 0;
+
+    return true;
+}
+
+void
+GLStateEGL::swap()
 {
     eglSwapBuffers(egl_display_, egl_surface_);
 }
 
 bool
-EGLState::gotValidDisplay()
+GLStateEGL::gotNativeConfig(int& vid)
+{
+    if (!gotValidConfig())
+        return false;
+
+    EGLint native_id;
+    if (!eglGetConfigAttrib(egl_display_, egl_config_, EGL_NATIVE_VISUAL_ID,
+        &native_id))
+    {
+        Log::debug("Failed to get native visual id for EGLConfig 0x%x\n", egl_config_);
+        return false;
+    }
+
+    vid = native_id;
+    return true;
+}
+
+void
+GLStateEGL::getVisualConfig(GLVisualConfig& vc)
+{
+    if (!gotValidConfig())
+        return;
+
+    get_glvisualconfig(egl_config_, vc);
+}
+
+/******************************
+ * GLStateEGL private methods *
+ *****************************/
+
+bool
+GLStateEGL::gotValidDisplay()
 {
     if (egl_display_)
         return true;
@@ -334,7 +442,7 @@ 
 }
 
 void
-EGLState::get_glvisualconfig(EGLConfig config, GLVisualConfig& visual_config)
+GLStateEGL::get_glvisualconfig(EGLConfig config, GLVisualConfig& visual_config)
 {
     eglGetConfigAttrib(egl_display_, config, EGL_BUFFER_SIZE, &visual_config.buffer);
     eglGetConfigAttrib(egl_display_, config, EGL_RED_SIZE, &visual_config.red);
@@ -346,7 +454,7 @@ 
 }
 
 EGLConfig
-EGLState::select_best_config(std::vector<EGLConfig>& configs)
+GLStateEGL::select_best_config(std::vector<EGLConfig>& configs)
 {
     int best_score(INT_MIN);
     EGLConfig best_config(0);
@@ -365,7 +473,7 @@ 
 
         get_glvisualconfig(config, vc);
 
-        score = vc.match_score(visual_config_);
+        score = vc.match_score(requested_visual_config_);
 
         if (score > best_score) {
             best_score = score;
@@ -377,7 +485,7 @@ 
 }
 
 bool
-EGLState::gotValidConfig()
+GLStateEGL::gotValidConfig()
 {
     if (egl_config_)
         return true;
@@ -386,12 +494,12 @@ 
         return false;
 
     const EGLint config_attribs[] = {
-        EGL_RED_SIZE, visual_config_.red,
-        EGL_GREEN_SIZE, visual_config_.green,
-        EGL_BLUE_SIZE, visual_config_.blue,
-        EGL_ALPHA_SIZE, visual_config_.alpha,
-        EGL_DEPTH_SIZE, visual_config_.depth,
-        EGL_STENCIL_SIZE, visual_config_.stencil,
+        EGL_RED_SIZE, requested_visual_config_.red,
+        EGL_GREEN_SIZE, requested_visual_config_.green,
+        EGL_BLUE_SIZE, requested_visual_config_.blue,
+        EGL_ALPHA_SIZE, requested_visual_config_.alpha,
+        EGL_DEPTH_SIZE, requested_visual_config_.depth,
+        EGL_STENCIL_SIZE, requested_visual_config_.stencil,
 #if USE_GLESv2
         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
 #elif USE_GL
@@ -436,7 +544,7 @@ 
         if (*configIt == egl_config_) {
             best_config_ = cfg;
         }
-    } 
+    }
 
     // Print out the config information, and let the user know the decision
     // about the "best" one with respect to the options.
@@ -459,7 +567,7 @@ 
 }
 
 bool
-EGLState::gotValidSurface()
+GLStateEGL::gotValidSurface()
 {
     if (egl_surface_)
         return true;
@@ -480,7 +588,7 @@ 
 }
 
 bool
-EGLState::gotValidContext()
+GLStateEGL::gotValidContext()
 {
     if (egl_context_)
         return true;
@@ -509,70 +617,3 @@ 
     return true;
 }
 
-bool
-EGLState::valid()
-{
-    if (!gotValidDisplay())
-        return false;
-
-    if (!gotValidConfig())
-        return false;
-
-    if (!gotValidSurface())
-        return false;
-
-    if (!gotValidContext())
-        return false;
-
-    if (egl_context_ == eglGetCurrentContext())
-        return true;
-
-    if (!eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_)) {
-        Log::error("eglMakeCurrent failed with error: 0x%x\n", eglGetError());
-        return false;
-    }
-
-    if (!eglSwapInterval(egl_display_, 0)) {
-        Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n");
-    }
-
-    return true;
-}
-
-bool
-EGLState::gotNativeConfig(int& vid)
-{
-    if (!gotValidConfig())
-        return false;
-
-    EGLint native_id;
-    if (!eglGetConfigAttrib(egl_display_, egl_config_, EGL_NATIVE_VISUAL_ID,
-        &native_id))
-    {
-        Log::debug("Failed to get native visual id for EGLConfig 0x%x\n", egl_config_);
-        return false;
-    }
-
-    vid = native_id;
-    return true;
-}
-
-bool
-EGLState::reset()
-{
-    if (!gotValidDisplay()) {
-        return false;
-    }
-
-    if (!egl_context_) {
-        return true;
-    }
-
-    if (EGL_FALSE == eglDestroyContext(egl_display_, egl_context_)) {
-        Log::debug("eglDestroyContext failed with error: 0x%x\n", eglGetError());
-    }
-
-    egl_context_ = 0;
-
-    return true;
-}

=== renamed file 'src/egl-state.h' => 'src/gl-state-egl.h'
--- src/egl-state.h	2012-12-05 22:19:12 +0000
+++ src/gl-state-egl.h	2013-03-01 14:58:03 +0000
@@ -19,11 +19,12 @@ 
 // Authors:
 //  Jesse Barker
 //
-#ifndef EGL_STATE_H_
-#define EGL_STATE_H_
+#ifndef GLMARK2_GL_STATE_EGL_H_
+#define GLMARK2_GL_STATE_EGL_H_
 
 #include <vector>
 #include <EGL/egl.h>
+#include "gl-state.h"
 #include "gl-visual-config.h"
 
 class EglConfig
@@ -113,7 +114,7 @@ 
     EGLint configID() const { return configID_; }
 };
 
-class EGLState
+class GLStateEGL : public GLState
 {
     EGLNativeDisplayType native_display_;
     EGLNativeWindowType native_window_;
@@ -121,7 +122,7 @@ 
     EGLConfig egl_config_;
     EGLContext egl_context_;
     EGLSurface egl_surface_;
-    GLVisualConfig visual_config_;
+    GLVisualConfig requested_visual_config_;
     EglConfig best_config_;
     bool gotValidDisplay();
     bool gotValidConfig();
@@ -130,22 +131,23 @@ 
     void get_glvisualconfig(EGLConfig config, GLVisualConfig& visual_config);
     EGLConfig select_best_config(std::vector<EGLConfig>& configs);
 public:
-    EGLState() :
+    GLStateEGL() :
         native_display_(0),
         native_window_(0),
         egl_display_(0),
         egl_config_(0),
         egl_context_(0),
         egl_surface_(0) {}
-    ~EGLState() {}
+
+    bool init_display(void* native_display, GLVisualConfig& config_pref);
+    bool init_surface(void* native_window);
+    void init_gl_extensions();
     bool valid();
-    bool init_display(EGLNativeDisplayType native_display, GLVisualConfig& config_pref);
-    bool init_surface(EGLNativeWindowType native_window);
     bool reset();
     void swap();
     // Performs a config search, returning a native visual ID on success
     bool gotNativeConfig(int& vid);
-    void getVisualConfig(GLVisualConfig& vc) { vc = visual_config_; }
+    void getVisualConfig(GLVisualConfig& vc);
 };
 
-#endif // EGL_STATE_H_
+#endif // GLMARK2_GL_STATE_EGL_H_

=== renamed file 'src/canvas-x11-glx.cpp' => 'src/gl-state-glx.cpp'
--- src/canvas-x11-glx.cpp	2012-12-06 17:54:57 +0000
+++ src/gl-state-glx.cpp	2013-03-03 10:18:39 +0000
@@ -1,5 +1,6 @@ 
 /*
  * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
  *
  * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
  *
@@ -17,37 +18,55 @@ 
  * glmark2.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Authors:
- *  Alexandros Frantzis (glmark2)
+ *  Alexandros Frantzis
  */
-#include "canvas-x11-glx.h"
+#include "gl-state-glx.h"
 #include "log.h"
 #include "options.h"
 
-#include <string>
 #include <climits>
 
-static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT_;
-static PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA_;
-static PFNGLXGETSWAPINTERVALMESAPROC glXGetSwapIntervalMESA_;
-
-/*********************
- * Protected methods *
- *********************/
-
-XVisualInfo *
-CanvasX11GLX::get_xvisualinfo()
+namespace
+{
+PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT_;
+PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA_;
+PFNGLXGETSWAPINTERVALMESAPROC glXGetSwapIntervalMESA_;
+}
+
+/******************
+ * Public methods *
+ ******************/
+
+bool
+GLStateGLX::init_display(void* native_display, GLVisualConfig& visual_config)
+{
+    xdpy_ = reinterpret_cast<Display*>(native_display);
+    requested_visual_config_ = visual_config;
+
+    return (xdpy_ != 0);
+}
+
+bool
+GLStateGLX::init_surface(void* native_window)
+{
+    xwin_ = reinterpret_cast<Window>(native_window);
+
+    return (xwin_ != 0);
+}
+
+void
+GLStateGLX::init_gl_extensions()
+{
+    GLExtensions::MapBuffer = glMapBuffer;
+    GLExtensions::UnmapBuffer = glUnmapBuffer;
+}
+
+bool
+GLStateGLX::valid()
 {
     if (!ensure_glx_fbconfig())
-        return 0;
-
-    XVisualInfo *vis_info = glXGetVisualFromFBConfig(xdpy_, glx_fbconfig_ );
-
-    return vis_info;
-}
-
-bool
-CanvasX11GLX::make_current()
-{
+        return false;
+
     if (!ensure_glx_context())
         return false;
 
@@ -61,6 +80,8 @@ 
         return false;
     }
 
+    init_gl_extensions();
+
     unsigned int desired_swap(0);
     unsigned int actual_swap(-1);
     if (glXSwapIntervalEXT_) {
@@ -82,13 +103,49 @@ 
     return true;
 }
 
-void
-CanvasX11GLX::get_glvisualconfig(GLVisualConfig &visual_config)
+
+bool
+GLStateGLX::reset()
+{
+    if (glx_context_)
+    {
+        glXDestroyContext(xdpy_, glx_context_);
+        glx_context_ = 0;
+    }
+
+    return true;
+}
+
+void
+GLStateGLX::swap()
+{
+    glXSwapBuffers(xdpy_, xwin_);
+}
+
+bool
+GLStateGLX::gotNativeConfig(int& vid)
+{
+    if (!ensure_glx_fbconfig())
+        return false;
+
+    int native_id;
+    if (glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_VISUAL_ID, &native_id) != Success)
+    {
+        Log::debug("Failed to get native visual id for GLXFBConfig 0x%x\n", glx_fbconfig_);
+        return false;
+    }
+
+    vid = native_id;
+    return true;
+}
+
+void
+GLStateGLX::getVisualConfig(GLVisualConfig& vc)
 {
     if (!ensure_glx_fbconfig())
         return;
 
-    get_glvisualconfig_glx(glx_fbconfig_, visual_config);
+    get_glvisualconfig_glx(glx_fbconfig_, vc);
 }
 
 /*******************
@@ -96,7 +153,7 @@ 
  *******************/
 
 bool
-CanvasX11GLX::check_glx_version()
+GLStateGLX::check_glx_version()
 {
     int glx_major, glx_minor;
 
@@ -111,7 +168,7 @@ 
 }
 
 void
-CanvasX11GLX::init_extensions()
+GLStateGLX::init_extensions()
 {
     /*
      * Parse the extensions we care about from the extension string.
@@ -159,20 +216,20 @@ 
 }
 
 bool
-CanvasX11GLX::ensure_glx_fbconfig()
+GLStateGLX::ensure_glx_fbconfig()
 {
     static int attribs[] = {
         GLX_X_RENDERABLE, True,
         GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
         GLX_RENDER_TYPE, GLX_RGBA_BIT,
         GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
-        GLX_RED_SIZE, visual_config_.red,
-        GLX_GREEN_SIZE, visual_config_.green,
-        GLX_BLUE_SIZE, visual_config_.blue,
-        GLX_ALPHA_SIZE, visual_config_.alpha,
-        GLX_DEPTH_SIZE, visual_config_.depth,
-        GLX_STENCIL_SIZE, visual_config_.stencil,
-        GLX_BUFFER_SIZE, visual_config_.buffer,
+        GLX_RED_SIZE, requested_visual_config_.red,
+        GLX_GREEN_SIZE, requested_visual_config_.green,
+        GLX_BLUE_SIZE, requested_visual_config_.blue,
+        GLX_ALPHA_SIZE, requested_visual_config_.alpha,
+        GLX_DEPTH_SIZE, requested_visual_config_.depth,
+        GLX_STENCIL_SIZE, requested_visual_config_.stencil,
+        GLX_BUFFER_SIZE, requested_visual_config_.buffer,
         GLX_DOUBLEBUFFER, True,
         None
     };
@@ -227,24 +284,8 @@ 
     return true;
 }
 
-void
-CanvasX11GLX::init_gl_extensions()
-{
-    GLExtensions::MapBuffer = glMapBuffer;
-    GLExtensions::UnmapBuffer = glUnmapBuffer;
-}
-
-bool
-CanvasX11GLX::reset_context()
-{
-    glXDestroyContext(xdpy_, glx_context_);
-    glx_context_ = 0;
-
-    return true;
-}
-
-bool
-CanvasX11GLX::ensure_glx_context()
+bool
+GLStateGLX::ensure_glx_context()
 {
     if (glx_context_)
         return true;
@@ -259,13 +300,12 @@ 
         return false;
     }
 
-    init_gl_extensions();
 
     return true;
 }
 
 void
-CanvasX11GLX::get_glvisualconfig_glx(const GLXFBConfig config, GLVisualConfig &visual_config)
+GLStateGLX::get_glvisualconfig_glx(const GLXFBConfig config, GLVisualConfig &visual_config)
 {
     glXGetFBConfigAttrib(xdpy_, config, GLX_BUFFER_SIZE, &visual_config.buffer);
     glXGetFBConfigAttrib(xdpy_, config, GLX_RED_SIZE, &visual_config.red);
@@ -277,7 +317,7 @@ 
 }
 
 GLXFBConfig
-CanvasX11GLX::select_best_config(std::vector<GLXFBConfig> configs)
+GLStateGLX::select_best_config(std::vector<GLXFBConfig> configs)
 {
     int best_score(INT_MIN);
     GLXFBConfig best_config(0);
@@ -296,7 +336,7 @@ 
 
         get_glvisualconfig_glx(config, vc);
 
-        score = vc.match_score(visual_config_);
+        score = vc.match_score(requested_visual_config_);
 
         if (score > best_score) {
             best_score = score;

=== renamed file 'src/canvas-x11-glx.h' => 'src/gl-state-glx.h'
--- src/canvas-x11-glx.h	2012-11-13 16:56:32 +0000
+++ src/gl-state-glx.h	2013-03-01 14:58:03 +0000
@@ -1,5 +1,6 @@ 
 /*
  * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
  *
  * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
  *
@@ -17,49 +18,50 @@ 
  * glmark2.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Authors:
- *  Alexandros Frantzis (glmark2)
+ *  Alexandros Frantzis
  */
-#ifndef GLMARK2_CANVAS_X11_GLX_H_
-#define GLMARK2_CANVAS_X11_GLX_H_
-
-#include "canvas-x11.h"
-
+#ifndef GLMARK2_GL_STATE_GLX_H_
+#define GLMARK2_GL_STATE_GLX_H_
+
+#include "gl-state.h"
+#include "gl-visual-config.h"
+#include "gl-headers.h"
+
+#include <vector>
+
+#include <X11/Xlib.h>
 #define GLX_GLXEXT_PROTOTYPES
 #include <GL/glx.h>
 #include <GL/glxext.h>
-#include <vector>
 
-/**
- * Canvas for rendering to an X11 window using GLX.
- */
-class CanvasX11GLX : public CanvasX11
+class GLStateGLX : public GLState
 {
 public:
-    CanvasX11GLX(int width, int height) :
-        CanvasX11(width, height), glx_fbconfig_(0), glx_context_(0) {}
-    ~CanvasX11GLX() {}
+    GLStateGLX()
+        : xdpy_(0), xwin_(0), glx_fbconfig_(0), glx_context_(0) {}
 
-protected:
-    XVisualInfo *get_xvisualinfo();
-    bool make_current();
-    bool reset_context();
-    void swap_buffers() { glXSwapBuffers(xdpy_, xwin_); }
-    void get_glvisualconfig(GLVisualConfig &visual_config);
-    bool init_gl_winsys() { return true; }
+    bool valid();
+    bool init_display(void* native_display, GLVisualConfig& config_pref);
+    bool init_surface(void* native_window);
+    void init_gl_extensions();
+    bool reset();
+    void swap();
+    bool gotNativeConfig(int& vid);
+    void getVisualConfig(GLVisualConfig& vc);
 
 private:
     bool check_glx_version();
     void init_extensions();
     bool ensure_glx_fbconfig();
     bool ensure_glx_context();
-    void init_gl_extensions();
     void get_glvisualconfig_glx(GLXFBConfig config, GLVisualConfig &visual_config);
     GLXFBConfig select_best_config(std::vector<GLXFBConfig> configs);
 
+    Display* xdpy_;
+    Window xwin_;
     GLXFBConfig glx_fbconfig_;
     GLXContext glx_context_;
-
+    GLVisualConfig requested_visual_config_;
 };
 
-#endif
-
+#endif /* GLMARK2_GL_STATE_GLX_H_ */

=== added file 'src/gl-state.h'
--- src/gl-state.h	1970-01-01 00:00:00 +0000
+++ src/gl-state.h	2013-03-01 14:58:03 +0000
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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:
+ *  Alexandros Frantzis
+ */
+#ifndef GLMARK2_GL_STATE_H_
+#define GLMARK2_GL_STATE_H_
+
+class GLVisualConfig;
+
+class GLState
+{
+public:
+    virtual ~GLState() {}
+
+    virtual bool init_display(void *native_display, GLVisualConfig& config_pref) = 0;
+    virtual bool init_surface(void *native_window) = 0;
+    virtual void init_gl_extensions() = 0;
+    virtual bool valid() = 0;
+    virtual bool reset() = 0;
+    virtual void swap() = 0;
+    virtual bool gotNativeConfig(int& vid) = 0;
+    virtual void getVisualConfig(GLVisualConfig& vc) = 0;
+};
+
+#endif /* GLMARK2_GL_STATE_H_ */

=== modified file 'src/main.cpp'
--- src/main.cpp	2012-12-18 15:42:46 +0000
+++ src/main.cpp	2013-03-01 14:57:51 +0000
@@ -35,12 +35,17 @@ 
 #include <iostream>
 #include <fstream>
 
+#include "canvas-generic.h"
+
 #if USE_DRM
-#include "canvas-drm.h"
+#include "native-state-drm.h"
+#include "gl-state-egl.h"
 #elif USE_GL
-#include "canvas-x11-glx.h"
+#include "native-state-x11.h"
+#include "gl-state-glx.h"
 #elif USE_GLESv2
-#include "canvas-x11-egl.h"
+#include "native-state-x11.h"
+#include "gl-state-egl.h"
 #endif
 
 using std::vector;
@@ -183,13 +188,18 @@ 
 
     // Create the canvas
 #if USE_DRM
-    CanvasDRM canvas(Options::size.first, Options::size.second);
+    NativeStateDRM native_state;
+    GLStateEGL gl_state;
 #elif USE_GL
-    CanvasX11GLX canvas(Options::size.first, Options::size.second);
+    NativeStateX11 native_state;
+    GLStateGLX gl_state;
 #elif USE_GLESv2
-    CanvasX11EGL canvas(Options::size.first, Options::size.second);
+    NativeStateX11 native_state;
+    GLStateEGL gl_state;
 #endif
 
+    CanvasGeneric canvas(native_state, gl_state, Options::size.first, Options::size.second);
+
     canvas.offscreen(Options::offscreen);
 
     canvas.visual_config(Options::visual_config);

=== added file 'src/native-state-drm.cpp'
--- src/native-state-drm.cpp	1970-01-01 00:00:00 +0000
+++ src/native-state-drm.cpp	2013-03-04 18:52:20 +0000
@@ -0,0 +1,355 @@ 
+/*
+ * Copyright Š 2012 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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
+ *  Alexandros Frantzis
+ */
+#include "native-state-drm.h"
+#include "log.h"
+#include <csignal>
+
+/******************
+ * Public methods *
+ ******************/
+
+bool
+NativeStateDRM::init_display()
+{
+    if (!dev_)
+        init();
+
+    return (dev_ != 0);
+}
+
+void*
+NativeStateDRM::display()
+{
+    return (void*)dev_;
+}
+
+bool
+NativeStateDRM::create_window(WindowProperties const& /*properties*/)
+{
+    if (!dev_) {
+        Log::error("Error: DRM device has not been initialized!\n");
+        return false;
+    }
+
+    return true;
+}
+
+void*
+NativeStateDRM::window(WindowProperties& properties)
+{
+    properties = WindowProperties(mode_->hdisplay,
+                                  mode_->vdisplay,
+                                  true, 0);
+    return (void*)surface_;
+}
+
+void
+NativeStateDRM::visible(bool /*visible*/)
+{
+}
+
+bool
+NativeStateDRM::should_quit()
+{
+    return should_quit_;
+}
+
+void
+NativeStateDRM::flip()
+{
+    gbm_bo* next = gbm_surface_lock_front_buffer(surface_);
+    fb_ = fb_get_from_bo(next);
+    unsigned int waiting(1);
+
+    if (!crtc_set_) {
+        int status = drmModeSetCrtc(fd_, encoder_->crtc_id, fb_->fb_id, 0, 0,
+                                    &connector_->connector_id, 1, mode_);
+        if (status >= 0) {
+            crtc_set_ = true;
+            bo_ = next;
+        }
+        else {
+            Log::error("Failed to set crtc: %d\n", status);
+        }
+        return;
+    }
+
+    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;
+}
+
+/*******************
+ * Private methods *
+ *******************/
+
+void
+NativeStateDRM::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);
+}
+
+NativeStateDRM::DRMFBState*
+NativeStateDRM::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
+NativeStateDRM::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
+NativeStateDRM::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, &NativeStateDRM::quit_handler);
+
+    return true;
+}
+
+bool NativeStateDRM::should_quit_ = false;
+
+void
+NativeStateDRM::quit_handler(int signo)
+{
+    Log::debug("Got SIGINT (%d).\n", signo);
+    should_quit_ = true;
+}
+
+void
+NativeStateDRM::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
+NativeStateDRM::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;
+}

=== added file 'src/native-state-drm.h'
--- src/native-state-drm.h	1970-01-01 00:00:00 +0000
+++ src/native-state-drm.h	2013-03-04 18:52:20 +0000
@@ -0,0 +1,91 @@ 
+/*
+ * Copyright Š 2012 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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
+ *  Alexandros Frantzis
+ */
+#ifndef GLMARK2_NATIVE_STATE_DRM_H_
+#define GLMARK2_NATIVE_STATE_DRM_H_
+
+#include "native-state.h"
+#include <cstring>
+#include <gbm.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+class NativeStateDRM : public NativeState
+{
+public:
+    NativeStateDRM() :
+        fd_(0),
+        resources_(0),
+        connector_(0),
+        encoder_(0),
+        mode_(0),
+        dev_(0),
+        surface_(0),
+        bo_(0),
+        fb_(0),
+        crtc_set_(false) {}
+    ~NativeStateDRM() { cleanup(); }
+
+    bool init_display();
+    void* display();
+    bool create_window(WindowProperties const& properties);
+    void* window(WindowProperties& properties);
+    void visible(bool v);
+    bool should_quit();
+    void flip();
+
+private:
+    struct DRMFBState
+    {
+        int fd;
+        gbm_bo* bo;
+        uint32_t fb_id;
+    };
+
+    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();
+    bool init();
+    void cleanup();
+
+    int fd_;
+    drmModeRes* resources_;
+    drmModeConnector* connector_;
+    drmModeEncoder* encoder_;
+    drmModeCrtcPtr crtc_;
+    drmModeModeInfo* mode_;
+    gbm_device* dev_;
+    gbm_surface* surface_;
+    gbm_bo* bo_;
+    DRMFBState* fb_;
+    bool crtc_set_;
+};
+
+#endif /* GLMARK2_NATIVE_STATE_DRM_H_ */

=== added file 'src/native-state-x11.cpp'
--- src/native-state-x11.cpp	1970-01-01 00:00:00 +0000
+++ src/native-state-x11.cpp	2013-03-01 14:48:17 +0000
@@ -0,0 +1,205 @@ 
+/*
+ * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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:
+ *  Alexandros Frantzis
+ */
+#include "native-state-x11.h"
+#include "log.h"
+
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+
+/******************
+ * Public methods *
+ ******************/
+
+NativeStateX11::~NativeStateX11()
+{
+    if (xdpy_)
+    {
+        if (xwin_)
+            XDestroyWindow(xdpy_, xwin_);
+
+        XCloseDisplay(xdpy_);
+    }
+}
+
+bool
+NativeStateX11::init_display()
+{
+    if (!xdpy_)
+        xdpy_ = XOpenDisplay(NULL);
+
+    return (xdpy_ != 0);
+}
+
+void*
+NativeStateX11::display()
+{
+    return (void*)xdpy_;
+}
+
+bool
+NativeStateX11::create_window(WindowProperties const& properties)
+{
+    static const char *win_name("glmark2 "GLMARK_VERSION);
+
+    if (!xdpy_) {
+        Log::error("Error: X11 Display has not been initialized!\n");
+        return false;
+    }
+
+    /* Recreate an existing window only if it has actually been resized */
+    if (xwin_) {
+        if (properties_.fullscreen != properties.fullscreen ||
+            (properties.fullscreen == false &&
+             (properties_.width != properties.width ||
+              properties_.height != properties.height)))
+        {
+            XDestroyWindow(xdpy_, xwin_);
+            xwin_ = 0;
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    /* Set desired attributes */
+    properties_.fullscreen = properties.fullscreen;
+    properties_.visual_id = properties.visual_id;
+
+    if (properties_.fullscreen) {
+        /* Get the screen (root window) size */
+        XWindowAttributes window_attr;
+        XGetWindowAttributes(xdpy_, RootWindow(xdpy_, DefaultScreen(xdpy_)), 
+                             &window_attr);
+        properties_.width = window_attr.width;
+        properties_.height = window_attr.height;
+    }
+    else {
+        properties_.width = properties.width;
+        properties_.height = properties.height;
+    }
+
+    XVisualInfo vis_tmpl;
+    XVisualInfo *vis_info = 0;
+    int num_visuals;
+
+    /* The X window visual must match the supplied visual id */
+    vis_tmpl.visualid = properties_.visual_id;
+    vis_info = XGetVisualInfo(xdpy_, VisualIDMask, &vis_tmpl,
+                             &num_visuals);
+    if (!vis_info) {
+        Log::error("Error: Could not get a valid XVisualInfo!\n");
+        return false;
+    }
+
+    Log::debug("Creating XWindow W: %d H: %d VisualID: 0x%x\n",
+               properties_.width, properties_.height, vis_info->visualid);
+
+    /* window attributes */
+    XSetWindowAttributes attr;
+    unsigned long mask;
+    Window root = RootWindow(xdpy_, DefaultScreen(xdpy_));
+
+    attr.background_pixel = 0;
+    attr.border_pixel = 0;
+    attr.colormap = XCreateColormap(xdpy_, root, vis_info->visual, AllocNone);
+    attr.event_mask = KeyPressMask;
+    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+    xwin_ = XCreateWindow(xdpy_, root, 0, 0, properties_.width, properties_.height,
+                          0, vis_info->depth, InputOutput,
+                          vis_info->visual, mask, &attr);
+
+    XFree(vis_info);
+
+    if (!xwin_) {
+        Log::error("Error: XCreateWindow() failed!\n");
+        return false;
+    }
+
+    /* set hints and properties */
+    if (properties_.fullscreen) {
+        Atom atom = XInternAtom(xdpy_, "_NET_WM_STATE_FULLSCREEN", True);
+        XChangeProperty(xdpy_, xwin_,
+                        XInternAtom(xdpy_, "_NET_WM_STATE", True),
+                        XA_ATOM, 32, PropModeReplace,
+                        reinterpret_cast<unsigned char*>(&atom),  1);
+    }
+    else {
+        XSizeHints sizehints;
+        sizehints.min_width  = properties_.width;
+        sizehints.min_height = properties_.height;
+        sizehints.max_width  = properties_.width;
+        sizehints.max_height = properties_.height;
+        sizehints.flags = PMaxSize | PMinSize;
+
+        XSetWMProperties(xdpy_, xwin_, NULL, NULL,
+                         NULL, 0, &sizehints, NULL, NULL);
+    }
+
+    /* Set the window name */
+    XStoreName(xdpy_ , xwin_,  win_name);
+
+    /* Gracefully handle Window Delete event from window manager */
+    Atom wmDelete = XInternAtom(xdpy_, "WM_DELETE_WINDOW", True);
+    XSetWMProtocols(xdpy_, xwin_, &wmDelete, 1);
+
+    return true;
+}
+
+void*
+NativeStateX11::window(WindowProperties& properties)
+{
+    properties = properties_;
+    return (void*)xwin_;
+}
+
+void
+NativeStateX11::visible(bool visible)
+{
+    if (visible)
+        XMapWindow(xdpy_, xwin_);
+}
+
+bool
+NativeStateX11::should_quit()
+{
+    XEvent event;
+
+    if (!XPending(xdpy_))
+        return false;
+
+    XNextEvent(xdpy_, &event);
+
+    if (event.type == KeyPress) {
+        if (XLookupKeysym(&event.xkey, 0) == XK_Escape)
+            return true;
+    }
+    else if (event.type == ClientMessage) {
+        /* Window Delete event from window manager */
+        return true;
+    }
+
+    return false;
+}

=== renamed file 'src/canvas-x11-egl.h' => 'src/native-state-x11.h'
--- src/canvas-x11-egl.h	2012-11-13 16:56:32 +0000
+++ src/native-state-x11.h	2013-03-01 14:48:17 +0000
@@ -1,5 +1,6 @@ 
 /*
  * Copyright Š 2010-2011 Linaro Limited
+ * Copyright Š 2013 Canonical Ltd
  *
  * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
  *
@@ -17,36 +18,34 @@ 
  * glmark2.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Authors:
- *  Alexandros Frantzis (glmark2)
- *  Jesse Barker
- */
-#ifndef GLMARK2_CANVAS_X11_EGL_H_
-#define GLMARK2_CANVAS_X11_EGL_H_
-
-#include "canvas-x11.h"
-#include "egl-state.h"
-
-/**
- * Canvas for rendering to an X11 window using EGL.
- */
-class CanvasX11EGL : public CanvasX11
+ *  Alexandros Frantzis
+ */
+#ifndef GLMARK2_NATIVE_STATE_X11_H_
+#define GLMARK2_NATIVE_STATE_X11_H_
+
+#include "native-state.h"
+#include <X11/Xlib.h>
+
+class NativeStateX11 : public NativeState
 {
 public:
-    CanvasX11EGL(int width, int height) :
-        CanvasX11(width, height) {}
-    ~CanvasX11EGL() {}
+    NativeStateX11() : xdpy_(0), xwin_(0), properties_() {}
+    ~NativeStateX11();
 
-protected:
-    XVisualInfo *get_xvisualinfo();
-    bool make_current();
-    bool reset_context();
-    void swap_buffers();
-    void get_glvisualconfig(GLVisualConfig &visual_config);
-    bool init_gl_winsys();
+    bool init_display();
+    void* display();
+    bool create_window(WindowProperties const& properties);
+    void* window(WindowProperties& properties);
+    void visible(bool v);
+    bool should_quit();
+    void flip() { }
 
 private:
-    void init_gl_extensions();
-    EGLState egl_;
+    /** The X display associated with this canvas. */
+    Display* xdpy_;
+    /** The X window associated with this canvas. */
+    Window xwin_;
+    WindowProperties properties_;
 };
 
-#endif
+#endif /* GLMARK2_NATIVE_STATE_X11_H_ */

=== added file 'src/native-state.h'
--- src/native-state.h	1970-01-01 00:00:00 +0000
+++ src/native-state.h	2013-03-01 14:48:17 +0000
@@ -0,0 +1,68 @@ 
+/*
+ * Copyright Š 2013 Canonical Ltd
+ *
+ * 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:
+ *  Alexandros Frantzis
+ */
+#ifndef GLMARK2_NATIVE_STATE_H_
+#define GLMARK2_NATIVE_STATE_H_
+
+class NativeState
+{
+public:
+    struct WindowProperties
+    {
+        WindowProperties(int w, int h, bool f, int v)
+            : width(w), height(h), fullscreen(f), visual_id(v) {}
+        WindowProperties()
+            : width(0), height(0), fullscreen(false), visual_id(0) {}
+
+        int width;
+        int height;
+        bool fullscreen;
+        int visual_id;
+    };
+
+    virtual ~NativeState() {}
+
+    /* Initializes the native display */
+    virtual bool init_display() = 0;
+
+    /* Gets the native display */
+    virtual void* display() = 0;
+
+    /* Creates (or recreates) the native window */
+    virtual bool create_window(WindowProperties const& properties) = 0;
+
+    /* 
+     * Gets the native window and its properties.
+     * The dimensions may be different than the ones requested.
+     */
+    virtual void* window(WindowProperties& properties) = 0;
+
+    /* Sets the visibility of the native window */
+    virtual void visible(bool v) = 0;
+
+    /* Whether the user has requested an exit */
+    virtual bool should_quit() = 0;
+
+    /* Flips the display */
+    virtual void flip() = 0;
+};
+
+#endif /* GLMARK2_NATIVE_STATE_H_ */

=== modified file 'src/wscript_build'
--- src/wscript_build	2012-12-06 21:29:19 +0000
+++ src/wscript_build	2013-03-01 14:57:51 +0000
@@ -1,11 +1,12 @@ 
 all_sources = bld.path.ant_glob('*.cpp scene-ideas/*.cc scene-terrain/*.cpp')
 common_sources = [f for f in all_sources if f.name.find('canvas-') == -1 and
                                             f.name.find('android') == -1 and
-                                            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']
+                                            f.name.find('native-state-') == -1 and
+                                            f.name.find('gl-state-') == -1]
+gl_sources = ['canvas-generic.cpp', 'native-state-x11.cpp', 'gl-state-glx.cpp']
+glesv2_sources = ['canvas-generic.cpp', 'native-state-x11.cpp', 'gl-state-egl.cpp']
+gl_drm_sources = ['canvas-generic.cpp', 'native-state-drm.cpp', 'gl-state-egl.cpp']
+glesv2_drm_sources = ['canvas-generic.cpp', 'native-state-drm.cpp', 'gl-state-egl.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']