From 7e36478d75d39f177ae41f2fa9471b2663cb6521 Mon Sep 17 00:00:00 2001
From: kui zheng <kui.zheng@arm.com>
Date: Wed, 16 Nov 2011 13:02:49 +0800
Subject: [PATCH] dircet: Add ARM NEON support:
  1. NEON Configuration.
  2. NEON Compiler checking.
  3. NEON Runtime detection.


Signed-off-by: kui zheng <kui.zheng@arm.com>
---
 configure.in                |   40 ++++++++++++++++++++++
 src/gfx/generic/Makefile.am |    4 ++-
 src/gfx/generic/generic.c   |   78 +++++++++++++++++++++++++++++++++++++++++-
 src/misc/conf.c             |   10 +++++
 src/misc/conf.h             |    1 +
 5 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/configure.in b/configure.in
index 02edba8..599e0ec 100644
--- a/configure.in
+++ b/configure.in
@@ -679,6 +679,12 @@ AC_ARG_ENABLE(sse,
                              [enable SSE support @<:@default=auto@:>@]),
               [], [enable_sse=$have_x86])
 
+AC_ARG_ENABLE(neon,
+              AC_HELP_STRING([--enable-neon],
+                             [enable NEON support @<:@default=auto@:>@]),
+              [], [enable_neon=$have_arm])
+
+
 if test "$enable_mmx" = "yes"; then
 
   dnl Necessary for assembler sources
@@ -732,6 +738,38 @@ fi
 AM_CONDITIONAL(BUILDMMX, test "$enable_mmx" = "yes")
 
 
+if test "$enable_neon" = "yes"; then
+
+  dnl Necessary for assembler sources
+  save_ac_ext="$ac_ext"
+  ac_ext=S
+  AC_MSG_CHECKING(whether the binutils support NEON)
+  save_CFLAGS="$CFLAGS"
+  
+  CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp"
+  echo "       VMOV.I8 Q0, #0x89" > conftest.S
+  if AC_TRY_EVAL(ac_compile); then
+	AC_DEFINE(USE_NEON,1,[Define to 1 if NEON assembly is available.])
+	AC_MSG_RESULT(yes)
+	DFB_NEON_CFLAGS="-mfpu=neon -mfloat-abi=softfp"
+  else
+	enable_neon=no
+ 	AC_MSG_RESULT(no)
+    	AC_MSG_WARN([
+****************************************************************
+ The installed assembler does not support the NEON command set.
+ Update your binutils package, if you want to compile NEON code.
+****************************************************************])
+  fi
+  
+  rm conftest*
+  ac_ext="$save_ac_ext"
+  CFLAGS="$save_CFLAGS"
+
+fi
+
+AM_CONDITIONAL(BUILDNEON, test "$enable_neon" = "yes")
+
 
 dnl Test for PVR2D system
 AC_ARG_ENABLE(pvr2d,
@@ -2003,6 +2041,7 @@ AC_SUBST(LIBPNG_LIBS)
 AC_SUBST(FREETYPE_PROVIDER)
 AC_SUBST(FREETYPE_CFLAGS)
 AC_SUBST(FREETYPE_LIBS)
+AC_SUBST(DFB_NEON_CFLAGS)
 
 AC_SUBST(DATADIR)
 AC_SUBST(MODULEDIR)
@@ -2207,6 +2246,7 @@ Misc options:
   Trace support             $enable_trace
   MMX support               $enable_mmx
   SSE support               $enable_sse
+  NEON support              $enable_neon
   Network support           $enable_network
   Include all strings       $enable_text
   Software Rendering        $with_software
diff --git a/src/gfx/generic/Makefile.am b/src/gfx/generic/Makefile.am
index 37696b7..227718c 100644
--- a/src/gfx/generic/Makefile.am
+++ b/src/gfx/generic/Makefile.am
@@ -7,7 +7,9 @@ INCLUDES = \
 	-I$(top_srcdir)/lib		\
 	-I$(top_srcdir)/src
 
-AM_CFLAGS = $(DFB_CFLAGS_OMIT_FRAME_POINTER)
+AM_CFLAGS = \
+	  $(DFB_CFLAGS_OMIT_FRAME_POINTER) \
+	  $(DFB_NEON_CFLAGS)
 
 internalincludedir = $(INTERNALINCLUDEDIR)/gfx/generic
 
diff --git a/src/gfx/generic/generic.c b/src/gfx/generic/generic.c
index 28763fa..1a4f73d 100644
--- a/src/gfx/generic/generic.c
+++ b/src/gfx/generic/generic.c
@@ -59,6 +59,11 @@
 #include <gfx/convert.h>
 #include <gfx/util.h>
 
+/* neon auto detection */
+#include <elf.h>
+#include <linux/auxvec.h>
+#include <asm/hwcap.h>
+
 #include "generic.h"
 #include "duffs_device.h"
 
@@ -77,11 +82,16 @@ static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff};
 
 
 static int use_mmx = 0;
+static int use_neon = 0;
 
 #ifdef USE_MMX
 static void gInit_MMX( void );
 #endif
 
+#ifdef USE_NEON
+static void gInit_NEON( void );
+#endif
+
 #if SIZEOF_LONG == 8
 static void gInit_64bit( void );
 #endif
@@ -8304,6 +8314,30 @@ static bool has_mmx( void )
 }
 #endif
 
+#ifdef USE_NEON
+static bool has_neon( void )
+{
+     Elf32_auxv_t aux;
+     uint32_t hwcap = 0;
+     int fd = -1;
+     fd = open ("/proc/self/auxv", O_RDONLY);
+     if (fd >= 0) {
+          while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) {
+               if (aux.a_type == AT_HWCAP) {
+                    hwcap = aux.a_un.a_val;
+                    /* hardcode these values to avoid depending on specific
+                     * versions of the hwcap header, e.g. HWCAP_NEON
+                     */
+                    /* this flag is only present on kernel 2.6.29 */
+                    return (hwcap & 4096) != 0;
+               }
+          }
+          close (fd);
+     }
+     return false;
+}
+#endif
+
 void gGetDriverInfo( GraphicsDriverInfo *info )
 {
      snprintf( info->name,
@@ -8336,6 +8370,24 @@ void gGetDriverInfo( GraphicsDriverInfo *info )
      }
 #endif
 
+#ifdef USE_NEON
+     if (has_neon()) {
+          if (!dfb_config->neon) {
+               D_INFO( "DirectFB/Genefx: NEON detected, but disabled by option 'no-neon'\n");
+          }
+          else {
+               gInit_NEON();
+
+               snprintf( info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
+                         "NEON Software Driver" );
+
+               D_INFO( "DirectFB/Genefx: NEON detected and enabled\n");
+          }
+     }
+     else {
+          D_INFO( "DirectFB/Genefx: No NEON detected\n" );
+     }
+#endif
      snprintf( info->vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, "directfb.org" );
 
      info->version.major = 0;
@@ -8346,9 +8398,13 @@ void gGetDeviceInfo( GraphicsDeviceInfo *info )
 {
      snprintf( info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH,
                "Software Rasterizer" );
-
-     snprintf( info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH,
+     if (use_neon) {
+	snprintf( info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "NEON");
+     }
+     else {
+        snprintf( info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH,
                use_mmx ? "MMX" : "Generic" );
+     }
 
      info->caps.accel    = DFXL_NONE;
      info->caps.flags    = 0;
@@ -9582,6 +9638,24 @@ static void gInit_MMX( void )
 #endif
 
 
+#ifdef USE_NEON
+
+/*
+#include "generic_neon.h"
+*/
+
+/*
+ * patches function pointers to NEON functions
+ */
+static void gInit_NEON( void )
+{
+     use_neon = 1;
+     /* to be added */
+}
+
+#endif
+
+
 #if SIZEOF_LONG == 8
 
 #include "generic_64.h"
diff --git a/src/misc/conf.c b/src/misc/conf.c
index 8ef4afd..03ca940 100644
--- a/src/misc/conf.c
+++ b/src/misc/conf.c
@@ -94,6 +94,9 @@ static const char *config_usage =
 #ifdef USE_MMX
      "  [no-]mmx                       Enable mmx support\n"
 #endif
+#ifdef USE_NEON
+     "  [no-]neon                      Enable neon support\n"
+#endif
      "  [no-]agp[=<mode>]              Enable AGP support\n"
      "  [no-]thrifty-surface-buffers   Free sysmem instance on xfer to video memory\n"
      "  font-format=<pixelformat>      Set the preferred font format\n"
@@ -412,6 +415,7 @@ static void config_allocate( void )
      dfb_config->banner                   = true;
      dfb_config->deinit_check             = true;
      dfb_config->mmx                      = true;
+     dfb_config->neon                     = true;
      dfb_config->vt                       = true;
      dfb_config->vt_switch                = true;
      dfb_config->vt_num                   = -1;
@@ -799,6 +803,12 @@ DFBResult dfb_config_set( const char *name, const char *value )
      if (strcmp (name, "no-mmx" ) == 0) {
           dfb_config->mmx = false;
      } else
+     if (strcmp (name, "neon" ) == 0) {
+          dfb_config->neon = true;
+     } else
+     if (strcmp (name, "no-neon" ) == 0) {
+          dfb_config->neon = false;
+     } else
      if (strcmp (name, "agp" ) == 0) {
           if (value) {
                int mode;
diff --git a/src/misc/conf.h b/src/misc/conf.h
index 6427510..3a2ce51 100644
--- a/src/misc/conf.h
+++ b/src/misc/conf.h
@@ -90,6 +90,7 @@ typedef struct
      bool      hardware_only;                     /* disable software fallbacks */
 
      bool      mmx;                               /* mmx support */
+     bool      neon;                              /* neon support */
 
      bool      banner;                            /* startup banner */
 
-- 
1.7.1

