From 7940d499d72eb136d07de31f8b589416337ca2df Mon Sep 17 00:00:00 2001
From: Madhurkiran Harikrishnan <madhurki@xilinx.com>
Date: Mon, 14 May 2018 14:13:18 -0700
Subject: [PATCH] fbdev: Add support for fbdev backend

This patch adds support for glmark2-es2-fbdev

Signed-off-by: Madhurkiran Harikrishnan <madhurki@xilinx.com>
Upstream Status: Pending

%% original patch: 0001-fbdev-Add-suppor-for-fbdev-backend.patch
---
 src/gl-state-egl.cpp       |   6 +-
 src/main.cpp               |   4 ++
 src/native-state-fbdev.cpp | 172 +++++++++++++++++++++++++++++++++++++++++++++
 src/native-state-fbdev.h   |  59 ++++++++++++++++
 src/wscript_build          |   7 +-
 wscript                    |   2 +
 6 files changed, 246 insertions(+), 4 deletions(-)
 create mode 100644 src/native-state-fbdev.cpp
 create mode 100644 src/native-state-fbdev.h

diff --git a/src/gl-state-egl.cpp b/src/gl-state-egl.cpp
index 3d6a091..ddf8446 100644
--- a/src/gl-state-egl.cpp
+++ b/src/gl-state-egl.cpp
@@ -443,9 +443,9 @@ GLStateEGL::gotValidDisplay()
     if (egl_display_)
         return true;
 
+#ifndef GLMARK2_USE_FBDEV
     char const * __restrict const supported_extensions =
         eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-
     if (supported_extensions
         && strstr(supported_extensions, "EGL_EXT_platform_base"))
     {
@@ -468,12 +468,14 @@ GLStateEGL::gotValidDisplay()
     {
         Log::debug("eglGetPlatformDisplayEXT() seems unsupported\n");
     }
-
     /* Just in case get_platform_display failed... */
     if (!egl_display_) {
         Log::debug("Falling back to eglGetDisplay()\n");
         egl_display_ = eglGetDisplay(native_display_);
     }
+#else
+    egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+#endif
 
     if (!egl_display_) {
         Log::error("eglGetDisplay() failed with error: 0x%x\n", eglGetError());
diff --git a/src/main.cpp b/src/main.cpp
index 6f7ceca..8db455e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,6 +36,8 @@
 
 #if GLMARK2_USE_X11
 #include "native-state-x11.h"
+#elif GLMARK2_USE_FBDEV
+#include "native-state-fbdev.h"
 #elif GLMARK2_USE_DRM
 #include "native-state-drm.h"
 #elif GLMARK2_USE_MIR
@@ -164,6 +166,8 @@ main(int argc, char *argv[])
     // Create the canvas
 #if GLMARK2_USE_X11
     NativeStateX11 native_state;
+#elif GLMARK2_USE_FBDEV
+    NativeStateFbdev native_state;
 #elif GLMARK2_USE_DRM
     NativeStateDRM native_state;
 #elif GLMARK2_USE_MIR
diff --git a/src/native-state-fbdev.cpp b/src/native-state-fbdev.cpp
new file mode 100644
index 0000000..0c82a25
--- /dev/null
+++ b/src/native-state-fbdev.cpp
@@ -0,0 +1,172 @@
+
+/*
+ * Copyright © 2018 Xilinx Inc
+ *
+ * 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:
+ *  Madhurkiran Harikrishnan <madhurkiran.harikrishnan@xilinx.com>
+ */
+
+#include <cstring>
+#include <csignal>
+#include <fcntl.h>
+#include <libudev.h>
+#include <linux/fb.h>
+#include "log.h"
+#include "native-state-fbdev.h"
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+volatile bool NativeStateFbdev::should_quit_ = false;
+
+NativeStateFbdev::~NativeStateFbdev()
+{
+    if (isvalid_fd(fd_)) {
+        close(fd_);
+        fd_ = -1;
+    }
+}
+
+bool
+NativeStateFbdev::init_display()
+{
+    struct sigaction new_action;
+
+    new_action.sa_handler = &NativeStateFbdev::quit_handler;
+    new_action.sa_flags = 0;
+    sigemptyset(&new_action.sa_mask);
+
+    sigaction(SIGINT, &new_action, NULL);
+    sigaction(SIGTERM, &new_action, NULL);
+
+    fd_ = get_fd();
+    if (!isvalid_fd(fd_)) {
+        Log::error("Failed to find a suitable FB device\n");
+        return false;
+    }
+
+    return true;
+}
+
+void*
+NativeStateFbdev::display()
+{
+    if (!isvalid_fd(fd_)) {
+        Log::error("Failed to initalize display\n");
+        return NULL;
+    }
+
+    return reinterpret_cast<void*>(fd_);
+}
+
+bool
+NativeStateFbdev::create_window(WindowProperties const& /*properties*/)
+{
+    if (!isvalid_fd(fd_)) {
+        Log::error("Failed to initalize display\n");
+	should_quit_ = true;
+        return false;
+    }
+
+    if (ioctl(fd_, FBIOGET_VSCREENINFO, &fb_info_)) {
+        Log::error("Failed to get Frame buffer info\n");
+	should_quit_ = true;
+        return false;
+    }
+    return true;
+}
+
+void*
+NativeStateFbdev::window(WindowProperties& properties)
+{
+    properties = WindowProperties(fb_info_.xres, fb_info_.yres, true, 0);
+
+    return 0;
+}
+
+void
+NativeStateFbdev::visible(bool /*visible*/)
+{
+}
+
+bool
+NativeStateFbdev::should_quit()
+{
+    return should_quit_;
+}
+
+void
+NativeStateFbdev::flip()
+{
+}
+
+void
+NativeStateFbdev::quit_handler(int /*signum*/)
+{
+    should_quit_ = true;
+}
+
+bool
+NativeStateFbdev::isvalid_fd(int fd)
+{
+    return fd >= 0;
+}
+
+int
+NativeStateFbdev::get_fd()
+{
+    std::string node_path;
+    struct fb_var_screeninfo fb_info;
+    int fd = -1, temp_fd;
+
+    Log::debug("Using Udev to detect the right fb node to use\n");
+    auto udev_cntx = udev_new();
+    auto dev_enum = udev_enumerate_new(udev_cntx);
+
+    udev_enumerate_add_match_sysname(dev_enum, "fb[0-9]*");
+    udev_enumerate_scan_devices(dev_enum);
+
+    Log::debug("Looking for the right fb node...\n");
+
+    auto entity = udev_enumerate_get_list_entry(dev_enum);
+
+    while (entity && !isvalid_fd(fd)) {
+        char const * __restrict entity_sys_path =
+	    udev_list_entry_get_name(entity);
+
+	if (entity_sys_path) {
+            struct udev_device* dev =
+	        udev_device_new_from_syspath(udev_cntx,
+					     entity_sys_path);
+	    const char * dev_node_path =
+	        udev_device_get_devnode(dev);
+
+	    temp_fd = open(dev_node_path, O_RDWR);
+
+	    if (!ioctl(temp_fd, FBIOGET_VSCREENINFO, &fb_info)) {
+                fd = temp_fd;
+		break;
+	    }
+
+	    udev_device_unref(dev);
+	}
+
+	entity = udev_list_entry_get_next(entity);
+    }
+
+    return fd;
+}
diff --git a/src/native-state-fbdev.h b/src/native-state-fbdev.h
new file mode 100644
index 0000000..0162ee0
--- /dev/null
+++ b/src/native-state-fbdev.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2018 Xilinx Inc
+ *
+ * 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:
+ *  Madhurkiran Harikrishnan <madhurkiran.harikrishnan@xilinx.com>
+ */
+
+#ifndef GLMARK2_NATIVE_STATE_FBDEV_H_
+#define GLMARK2_NATIVE_STATE_FBDEV_H_
+
+#include <csignal>
+#include <cstring>
+#include <EGL/egl.h>
+#include <EGL/eglplatform.h>
+#include <linux/fb.h>
+#include "native-state.h"
+
+class NativeStateFbdev : public NativeState
+{
+public:
+    NativeStateFbdev() :
+        fd_(-1),
+        native_window_((EGLNativeWindowType)NULL) {}
+    ~NativeStateFbdev();
+
+    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:
+    int fd_;
+    struct fb_var_screeninfo fb_info_;
+    NativeWindowType native_window_;
+    static volatile bool should_quit_;
+    static void quit_handler(int signum);
+    static bool isvalid_fd(int fd);
+    static int get_fd();
+};
+
+#endif /* GLMARK2_NATIVE_STATE_FBDEV_H_ */
diff --git a/src/wscript_build b/src/wscript_build
index 9b24f8b..00cbe37 100644
--- a/src/wscript_build
+++ b/src/wscript_build
@@ -21,7 +21,8 @@ flavor_sources = {
   'mir-gl' : common_flavor_sources + ['native-state-mir.cpp', 'gl-state-egl.cpp'],
   'mir-glesv2' : common_flavor_sources + ['native-state-mir.cpp', 'gl-state-egl.cpp'],
   'wayland-gl' : common_flavor_sources + ['native-state-wayland.cpp', 'gl-state-egl.cpp'],
-  'wayland-glesv2' : common_flavor_sources + ['native-state-wayland.cpp', 'gl-state-egl.cpp']
+  'wayland-glesv2' : common_flavor_sources + ['native-state-wayland.cpp', 'gl-state-egl.cpp'],
+  'fbdev-glesv2' :  common_flavor_sources + ['native-state-fbdev.cpp', 'gl-state-egl.cpp']
 }
 flavor_uselibs = {
   'x11-gl' : ['x11', 'gl', 'matrix-gl', 'common-gl'],
@@ -32,11 +33,13 @@ flavor_uselibs = {
   'mir-gl' : ['mirclient', 'egl', 'gl', 'matrix-gl', 'common-gl'],
   'mir-glesv2' : ['mirclient', 'egl', 'glesv2', 'matrix-glesv2', 'common-glesv2'],
   'wayland-gl' : ['wayland-client', 'wayland-egl', 'egl', 'gl', 'matrix-gl', 'common-gl'],
-  'wayland-glesv2' : ['wayland-client', 'wayland-egl', 'egl', 'glesv2', 'matrix-glesv2', 'common-glesv2']
+  'wayland-glesv2' : ['wayland-client', 'wayland-egl', 'egl', 'glesv2', 'matrix-glesv2', 'common-glesv2'],
+  'fbdev-glesv2' : ['drm', 'udev', 'egl', 'glesv2', 'matrix-glesv2', 'common-glesv2']
 }
 flavor_defines = {
   'x11-gl' : ['GLMARK2_USE_X11', 'GLMARK2_USE_GL', 'GLMARK2_USE_GLX'],
   'x11-glesv2' : ['GLMARK2_USE_X11', 'GLMARK2_USE_GLESv2', 'GLMARK2_USE_EGL'],
+  'fbdev-glesv2' : ['GLMARK2_USE_FBDEV', 'GLMARK2_USE_GLESv2', 'GLMARK2_USE_EGL', 'MESA_EGL_NO_X11_HEADERS'],
   'drm-gl' : ['GLMARK2_USE_DRM', 'GLMARK2_USE_GL', 'GLMARK2_USE_EGL', '__GBM__'],
   'drm-glesv2' : ['GLMARK2_USE_DRM', 'GLMARK2_USE_GLESv2', 'GLMARK2_USE_EGL', '__GBM__'],
   'mir-gl' : ['GLMARK2_USE_MIR', 'GLMARK2_USE_GL', 'GLMARK2_USE_EGL'],
diff --git a/wscript b/wscript
index c0e779f..ed602b8 100644
--- a/wscript
+++ b/wscript
@@ -12,6 +12,7 @@ FLAVORS = {
     'x11-glesv2' : 'glmark2-es2',
     'drm-gl' : 'glmark2-drm',
     'drm-glesv2' : 'glmark2-es2-drm',
+    'fbdev-glesv2' : 'glmark2-es2-fbdev',
     'mir-gl' : 'glmark2-mir',
     'mir-glesv2' : 'glmark2-es2-mir',
     'wayland-gl' : 'glmark2-wayland',
@@ -129,6 +130,7 @@ def configure(ctx):
                 ('libdrm','drm', None, list_contains(ctx.options.flavors, 'drm')),
                 ('gbm','gbm', None, list_contains(ctx.options.flavors, 'drm')),
                 ('libudev', 'udev', None, list_contains(ctx.options.flavors, 'drm')),
+                ('libudev', 'udev', None, list_contains(ctx.options.flavors, 'fbdev')),
                 ('mirclient','mirclient', '0.13', list_contains(ctx.options.flavors, 'mir')),
                 ('wayland-client','wayland-client', None, list_contains(ctx.options.flavors, 'wayland')),
                 ('wayland-egl','wayland-egl', None, list_contains(ctx.options.flavors, 'wayland'))]
-- 
2.7.4

