Brand new DirectFB engine.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 9 Sep 2008 20:27:58 +0000 (20:27 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 9 Sep 2008 20:27:58 +0000 (20:27 +0000)
ProFUSION funded the rework of DirectFB engine, it works quite well,
please report problems with it and be sure to try to uncomment the
following lines to see if it helps:

evas_engine.c: (uncomment if you notice problems)
    //#define DFB_USE_EVAS_IMAGE_DRAW 1
    //#define DFB_USE_EVAS_RECT_DRAW 1
    //#define DFB_USE_EVAS_POLYGON_DRAW 1
    //#define DFB_UPDATE_INDIVIDUAL_RECTS 1

polygon.c: (comment if you notice slowdowns, but may lead to visual problems)
    #define USE_SPAN_RECTS 1

You can also turn on debug by uncommenting in evas_engine.c:
    //#define DFB_DEBUG_IMAGE 1
    //#define DFB_DEBUG_FLAGS 1
    //#define DFB_DEBUG_ACCELERATION 1

Thanks to Denis Oliver Kropp (dok) for review and patches!

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@35904 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

Makefile.am
configure.in
src/modules/engines/Makefile.am
src/modules/engines/directfb/Evas_Engine_DirectFB.h [new file with mode: 0644]
src/modules/engines/directfb/Makefile.am [new file with mode: 0644]
src/modules/engines/directfb/evas_engine.c [new file with mode: 0644]
src/modules/engines/directfb/evas_engine.h [new file with mode: 0644]
src/modules/engines/directfb/polygon.c [new file with mode: 0644]

index 5b16b84..8015a3e 100644 (file)
@@ -88,9 +88,9 @@ if BUILD_ENGINE_SOFTWARE_XCB
 psoftwarexcb = evas-software-xcb.pc
 endif
 
-#if BUILD_ENGINE_DIRECTFB
-#pdirectfb = evas-directfb.pc
-#endif
+if BUILD_ENGINE_DIRECTFB
+pdirectfb = evas-directfb.pc
+endif
 
 if BUILD_ENGINE_FB
 pfb = evas-fb.pc
index e5a3e1d..599354f 100644 (file)
@@ -405,30 +405,30 @@ AM_CONDITIONAL(BUILD_ENGINE_SOFTWARE_XCB, test "x$have_evas_software_xcb" = "xye
 
 #######################################
 ## Check if we should build the directfb engine
-#want_evas_directfb="no";
-#have_evas_directfb="no";
-#
-#AC_MSG_CHECKING(whether directfb backend is to be built)
-#AC_ARG_ENABLE(directfb,
-#  AC_HELP_STRING([--enable-directfb], [enable the DirectFB rendering backend]),
-#  [ want_evas_directfb=$enableval ]
-#)
-#AC_MSG_RESULT($want_evas_directfb)
-#
-#if test "x$want_evas_directfb" = "xyes"; then
-#  PKG_CHECK_MODULES(DIRECTFB, directfb >= 0.9.16,
-#    [
-#      AC_DEFINE(BUILD_ENGINE_DIRECTFB, 1, [DirectFB Rendering Backend])
-#      have_evas_directfb="yes"
-#    ],
-#    [
-#      if test "x$want_evas_directfb" = "xyes" -a "x$use_strict" = "xyes" ; then
-#        AC_MSG_ERROR([DirectFB not found (strict dependencies checking)])
-#      fi
-#    ]
-#  )
-#fi
-#AM_CONDITIONAL(BUILD_ENGINE_DIRECTFB, test "x$have_evas_directfb" = "xyes")
+want_evas_directfb="no";
+have_evas_directfb="no";
+
+AC_MSG_CHECKING(whether directfb backend is to be built)
+AC_ARG_ENABLE(directfb,
+  AC_HELP_STRING([--enable-directfb], [enable the DirectFB rendering backend]),
+  [ want_evas_directfb=$enableval ]
+)
+AC_MSG_RESULT($want_evas_directfb)
+
+if test "x$want_evas_directfb" = "xyes"; then
+  PKG_CHECK_MODULES(DIRECTFB, directfb >= 0.9.16,
+    [
+      AC_DEFINE(BUILD_ENGINE_DIRECTFB, 1, [DirectFB Rendering Backend])
+      have_evas_directfb="yes"
+    ],
+    [
+      if test "x$want_evas_directfb" = "xyes" -a "x$use_strict" = "xyes" ; then
+        AC_MSG_ERROR([DirectFB not found (strict dependencies checking)])
+      fi
+    ]
+  )
+fi
+AM_CONDITIONAL(BUILD_ENGINE_DIRECTFB, test "x$have_evas_directfb" = "xyes")
 
 #######################################
 ## Check if we should build the sdl engine
@@ -1653,6 +1653,7 @@ AC_SUBST(pthread_libs)
 AC_OUTPUT([
 Makefile
 evas-cairo-x11.pc
+evas-directfb.pc
 evas-fb.pc
 evas-glitz-x11.pc
 evas-opengl-glew.pc
@@ -1698,6 +1699,7 @@ src/modules/engines/fb/Makefile
 src/modules/engines/buffer/Makefile
 src/modules/engines/software_win32_gdi/Makefile
 src/modules/engines/software_qtopia/Makefile
+src/modules/engines/directfb/Makefile
 src/modules/engines/gl_common/Makefile
 src/modules/engines/gl_glew/Makefile
 src/modules/engines/gl_x11/Makefile
@@ -1764,6 +1766,7 @@ echo "  Software 16bit X11.........: $have_evas_software_16_x11"
 echo "  Software 16bit Directdraw..: $have_evas_software_16_ddraw"
 echo "  Software 16bit WinCE.......: $have_evas_software_16_wince"
 echo "  Software 16bit SDL.........: $have_evas_sdl (primitive: $sdl_primitive)"
+echo "  DirectFB...................: $have_evas_directfb"
 # FIXME: opengl engine needs to be fixed and tested lots for all drivers
 # FIXME: xrender engine to be written
 echo
index 22e311b..59df875 100644 (file)
@@ -5,6 +5,7 @@ software_generic \
 buffer \
 cairo_common \
 cairo_x11 \
+directfb \
 fb \
 gl_common \
 gl_x11 \
diff --git a/src/modules/engines/directfb/Evas_Engine_DirectFB.h b/src/modules/engines/directfb/Evas_Engine_DirectFB.h
new file mode 100644 (file)
index 0000000..f4177e1
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _EVAS_ENGINE_DIRECTFB_H
+#define _EVAS_ENGINE_DIRECTFB_H
+
+#include <Evas.h>
+#include <directfb/directfb.h>
+
+typedef struct _Evas_Engine_Info_DirectFB Evas_Engine_Info_DirectFB;
+
+struct _Evas_Engine_Info_DirectFB
+{
+   /* PRIVATE - don't mess with this baby or evas will poke its tongue out */
+   /* at you and make nasty noises */
+   Evas_Engine_Info magic;
+
+   struct Evas_Engine_DirectFB_Spec {
+      IDirectFB                 *dfb;
+      IDirectFBSurface          *surface;
+   } info;
+};
+#endif
+
+
diff --git a/src/modules/engines/directfb/Makefile.am b/src/modules/engines/directfb/Makefile.am
new file mode 100644 (file)
index 0000000..1353401
--- /dev/null
@@ -0,0 +1,31 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-I$(top_srcdir)/src/modules/engines \
+@FREETYPE_CFLAGS@ \
+@DIRECTFB_CFLAGS@
+
+AM_CFLAGS = @WIN32_CFLAGS@
+
+if BUILD_ENGINE_DIRECTFB
+
+pkgdir = $(libdir)/evas/modules/engines/directfb/$(MODULE_ARCH)
+
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES  = evas_engine.c polygon.c
+
+module_la_LIBADD = @DIRECTFB_LIBS@ $(top_builddir)/src/lib/libevas.la
+module_la_LDFLAGS = @lt_no_undefined@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
+module_la_DEPENDENCIES = $(top_builddir)/config.h
+
+include_HEADERS = Evas_Engine_DirectFB.h
+
+endif
+
+EXTRA_DIST = evas_engine.h
diff --git a/src/modules/engines/directfb/evas_engine.c b/src/modules/engines/directfb/evas_engine.c
new file mode 100644 (file)
index 0000000..79b5d0b
--- /dev/null
@@ -0,0 +1,1639 @@
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include "evas_engine.h"
+
+/* Uses Evas own image_draw primitive, for comparison purposes only. */
+//#define DFB_USE_EVAS_IMAGE_DRAW 1
+//#define DFB_USE_EVAS_RECT_DRAW 1
+//#define DFB_USE_EVAS_POLYGON_DRAW 1
+//#define DFB_UPDATE_INDIVIDUAL_RECTS 1
+#define DFB_FLIP_FLAGS DSFLIP_NONE
+//#define DFB_FLIP_FLAGS (DSFLIP_ONSYNC | DSFLIP_WAIT)
+
+/* Turn on debug */
+//#define DFB_DEBUG_IMAGE 1
+//#define DFB_DEBUG_FLAGS 1
+//#define DFB_DEBUG_ACCELERATION 1
+
+static Evas_Func func = {};
+static Evas_Func parent_func = {};
+static IDirectFB *dfb = NULL; /* XXX HACK to work around evas image cache
+                              * lack of extra data. Fix it instead later.
+                              */
+
+
+/***********************************************************************
+ * Evas helpers
+ **********************************************************************/
+static void
+_rect_set(Evas_Rectangle *r, int x, int y, int w, int h)
+{
+   r->x = x;
+   r->y = y;
+   r->w = w;
+   r->h = h;
+}
+
+static void
+_context_get_color(RGBA_Draw_Context *dc, int *r, int *g, int *b, int *a)
+{
+   DATA32 col;
+
+   if (dc->mul.use)
+     col = dc->mul.col;
+   else
+     col = dc->col.col;
+
+   *r = R_VAL(&col);
+   *g = G_VAL(&col);
+   *b = B_VAL(&col);
+   *a = A_VAL(&col);
+}
+
+
+/***********************************************************************
+ * DirectFB helpers
+ **********************************************************************/
+static void
+_dfb_surface_clear(IDirectFBSurface *surface, int x, int y, int w, int h)
+{
+   DFBRegion cr;
+   DFBResult r;
+
+   cr.x1 = x;
+   cr.y1 = y;
+   cr.x2 = x + w - 1;
+   cr.y2 = y + h - 1;
+   r = surface->SetClip(surface, &cr);
+   if (r != DFB_OK)
+     goto error;
+
+   r = surface->Clear(surface, 0, 0, 0, 0);
+   if (r != DFB_OK)
+     goto error;
+
+   return;
+
+ error:
+   fprintf(stderr, "ERROR: could not clear surface: %s\n",
+          DirectFBErrorString(r));
+}
+
+static void
+_image_clear(DirectFB_Engine_Image_Entry *image, int x, int y, int w, int h)
+{
+   if (image->cache_entry.src->flags.alpha)
+     _dfb_surface_clear(image->surface, x, y, w, h);
+}
+
+static void
+_image_autoset_alpha(DirectFB_Engine_Image_Entry *image)
+{
+   DFBResult r;
+   DFBSurfacePixelFormat fmt;
+   IDirectFBSurface *surface;
+   RGBA_Image *im;
+   int has_alpha;
+
+   surface = image->surface;
+   r = surface->GetPixelFormat(surface, &fmt);
+   if (r != DFB_OK)
+     {
+       fprintf(stderr, "ERROR: could not get pixel format: %s\n",
+               DirectFBErrorString(r));
+       return;
+     }
+
+   /* XXX: check this in more depth in future, if other PF are supported */
+   image->cache_entry.src->flags.alpha = (fmt == DSPF_ARGB);
+}
+
+static void
+_dfb_surface_update(IDirectFBSurface *surface, int x, int y, int w, int h)
+{
+   DFBRegion cr;
+   DFBResult r;
+
+   cr.x1 = x;
+   cr.y1 = y;
+   cr.x2 = x + w - 1;
+   cr.y2 = y + h - 1;
+   r = surface->Flip(surface, &cr, DSFLIP_NONE);
+   if (r != DFB_OK)
+     fprintf(stderr, "ERROR: could not update surface: %s\n",
+            DirectFBErrorString(r));
+}
+
+static IDirectFBSurface *
+_dfb_surface_from_data(IDirectFB *dfb, int w, int h, void *data)
+{
+   IDirectFBSurface *s;
+   DFBSurfaceDescription desc;
+   DFBResult r;
+
+   desc.flags = (DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT |
+                DSDESC_PIXELFORMAT | DSDESC_PREALLOCATED);
+   desc.caps = DSCAPS_PREMULTIPLIED;
+   desc.width = w;
+   desc.height = h;
+   desc.preallocated[0].data = data;
+   desc.preallocated[0].pitch = w * 4;
+   desc.preallocated[1].data = NULL;
+   desc.preallocated[1].pitch = 0;
+   desc.pixelformat = DSPF_ARGB;
+   r = dfb->CreateSurface(dfb, &desc, &s);
+   if (r != DFB_OK)
+     {
+       fprintf(stderr, "ERROR: cannot create DirectFB surface: %s\n",
+               DirectFBErrorString(r));
+       return NULL;
+     }
+
+   s->SetPorterDuff(s, DSPD_SRC_OVER);
+
+   return s;
+}
+
+static void
+_dfb_surface_free(IDirectFBSurface *surface)
+{
+   if (surface)
+     surface->Release(surface);
+}
+
+static void
+_dfb_blit_accel_caps_print(IDirectFBSurface *dst, IDirectFBSurface *src)
+{
+#ifdef DFB_DEBUG_ACCELERATION
+   DFBAccelerationMask mask;
+   DFBResult r;
+
+   r = dst->GetAccelerationMask(dst, src, &mask);
+   if (r != DFB_OK)
+     {
+       fprintf(stderr, "ERROR: Could not retrieve acceleration mask: %s\n",
+               DirectFBErrorString(r));
+       return;
+     }
+
+   fputs("Acceleration: ", stderr);
+
+#define O(m) if (mask & m) fputs(#m " ", stderr)
+   O(DFXL_FILLRECTANGLE);
+   O(DFXL_DRAWRECTANGLE);
+   O(DFXL_DRAWLINE);
+   O(DFXL_FILLTRIANGLE);
+   O(DFXL_BLIT);
+   O(DFXL_STRETCHBLIT);
+   O(DFXL_TEXTRIANGLES);
+   O(DFXL_DRAWSTRING);
+#undef O
+
+   if (mask == DFXL_NONE) fputs("<NONE>", stderr);
+   fputc('\n', stderr);
+#endif /* DFB_DEBUG_ACCELERATION */
+}
+
+#ifdef DFB_DEBUG_FLAGS
+static const char *
+_dfb_blit_flags_str(DFBSurfaceBlittingFlags flags)
+{
+   static char buf[1024];
+
+   buf[0] = 0;
+
+#define T(m, n)                                        \
+   do {                                                \
+      if (flags & m) {                         \
+        if (buf[0] != 0) strcat(buf, " | ");   \
+        strcat(buf, n);                        \
+      }                                                \
+   } while (0)
+
+   T(DSBLIT_BLEND_ALPHACHANNEL, "BLEND_ALPHACHANNEL");
+   T(DSBLIT_BLEND_COLORALPHA, "BLEND_COLORALPHA");
+   T(DSBLIT_COLORIZE, "COLORIZE");
+   T(DSBLIT_SRC_COLORKEY, "SRC_COLORKEY");
+   T(DSBLIT_DST_COLORKEY, "DST_COLORKEY");
+   T(DSBLIT_SRC_PREMULTIPLY, "SRC_PREMULTIPLY");
+   T(DSBLIT_DST_PREMULTIPLY, "DST_PREMULTIPLY");
+   T(DSBLIT_DEMULTIPLY, "DEMULTIPLY");
+   T(DSBLIT_DEINTERLACE, "DSBLIT_DEINTERLACE");
+   T(DSBLIT_SRC_PREMULTCOLOR, "SRC_PREMULTCOLOR");
+   T(DSBLIT_XOR, "XOR");
+   T(DSBLIT_INDEX_TRANSLATION, "INDEX_TRANSLATION");
+#undef T
+
+   if (buf[0] == 0)
+     strcpy(buf, "NOFX");
+
+   return buf;
+}
+
+static const char *
+_dfb_draw_flags_str(DFBSurfaceDrawingFlags flags)
+{
+   static char buf[1024];
+
+   buf[0] = 0;
+
+#define T(m, n)                                        \
+   do {                                                \
+      if (flags & m) {                         \
+        if (buf[0] != 0) strcat(buf, " | ");   \
+        strcat(buf, n);                        \
+      }                                                \
+   } while (0)
+   T(DSDRAW_BLEND, "BLEND");
+   T(DSDRAW_DST_COLORKEY, "DST_COLORKEY");
+   T(DSDRAW_SRC_PREMULTIPLY, "SRC_PREMULTIPLY");
+   T(DSDRAW_DST_PREMULTIPLY, "DST_PREMULTIPLY");
+   T(DSDRAW_DEMULTIPLY, "DEMULTIPLY");
+   T(DSDRAW_XOR, "DSDRAW_XOR");
+#undef T
+   if (buf[0] == 0)
+     strcpy(buf, "NOFX");
+
+   return buf;
+}
+
+static const char *
+_dfb_blend_func_str(DFBSurfaceBlendFunction func)
+{
+   static char *names[] = {
+     "ZERO",
+     "ONE",
+     "SRCCOLOR",
+     "INVSRCCOLOR",
+     "SRCALPHA",
+     "INVSRCALPHA",
+     "DESTALPHA",
+     "INVDESTALPHA",
+     "DESTCOLOR",
+     "INVDESTCOLOR",
+     "SRCALPHASAT"
+   };
+   func--;
+   if ((func >= 0) && (func <= sizeof(names)/sizeof(*names)))
+     return names[func];
+   else
+     return NULL;
+}
+#endif /* DFB_DEBUG_FLAGS */
+
+int
+_dfb_surface_set_color_from_context(IDirectFBSurface *surface, RGBA_Draw_Context *dc)
+{
+   DFBSurfaceDrawingFlags flags;
+   int r, g, b, a;
+   DFBResult res;
+
+   _context_get_color(dc, &r, &g, &b, &a);
+   if (a == 0)
+     return 0;
+
+   r = 0xff * r / a;
+   g = 0xff * g / a;
+   b = 0xff * b / a;
+
+   res = surface->SetColor(surface, r, g, b, a);
+   if (res != DFB_OK)
+     goto error;
+
+   flags = (a != 255) ? DSDRAW_BLEND : DSDRAW_NOFX;
+   res = surface->SetDrawingFlags(surface, flags);
+   if (res != DFB_OK)
+     goto error;
+
+#ifdef DFB_DEBUG_FLAGS
+   printf("DRAW: color=%d %d %d %d, flags=%s\n",
+         r, g, b, a, _dfb_draw_flags_str(flags));
+#endif /* DFB_DEBUG_FLAGS */
+
+   return 1;
+
+ error:
+   fprintf(stderr, "ERROR: could not set color from context: %s\n",
+          DirectFBErrorString(res));
+   return 0;
+}
+
+static int
+_dfb_surface_set_blit_params(DirectFB_Engine_Image_Entry *d, DirectFB_Engine_Image_Entry *s, RGBA_Draw_Context *dc)
+{
+   IDirectFBSurface *surface;
+   DFBSurfaceBlittingFlags blit_flags = DSBLIT_NOFX;
+   DFBResult res;
+   int r, g, b, a;
+
+   _context_get_color(dc, &r, &g, &b, &a);
+   if (a == 0)
+     return 0;
+
+   if (a != 255)
+     blit_flags = DSBLIT_BLEND_COLORALPHA | DSBLIT_SRC_PREMULTCOLOR;
+
+   if ((r != a) || (g != a) || (b != a))
+     {
+       blit_flags |= DSBLIT_COLORIZE;
+
+       r = 0xff * r / a;
+       g = 0xff * g / a;
+       b = 0xff * b / a;
+   }
+
+   if (s->cache_entry.src->flags.alpha)
+     blit_flags |= DSBLIT_BLEND_ALPHACHANNEL;
+
+   surface = d->surface;
+
+   if (blit_flags &
+       (DSBLIT_BLEND_COLORALPHA | DSBLIT_SRC_PREMULTCOLOR | DSBLIT_COLORIZE))
+     {
+       res = surface->SetColor(surface, r, g, b, a);
+       if (res != DFB_OK)
+         goto error;
+     }
+
+   res = surface->SetBlittingFlags(surface, blit_flags);
+   if (res != DFB_OK)
+     goto error;
+
+#ifdef DFB_DEBUG_FLAGS
+   printf("BLIT: sfunc=%s, dfunc=%s, color=%d %d %d %d\n\tblit=%s\n\tdraw=%s\n",
+         _dfb_blend_func_str(src_func), _dfb_blend_func_str(dst_func),
+         r, g, b, a,
+         _dfb_blit_flags_str(blit_flags), _dfb_draw_flags_str(draw_flags));
+#endif /* DFB_DEBUG_FLAGS */
+
+   return 1;
+
+ error:
+   fprintf(stderr, "ERROR: Could not set blit params: %s\n",
+          DirectFBErrorString(res));
+   return 0;
+}
+
+static int
+_dfb_lock_and_sync_image(IDirectFBSurface *surface, RGBA_Image *image, DFBSurfaceLockFlags flags)
+{
+   DFBResult r;
+   int pitch, sw, sh;
+   void *pixels;
+
+   r = surface->GetSize(surface, &sw, &sh);
+   if (r != DFB_OK)
+     return 0;
+
+   r = surface->Lock(surface, flags, &pixels, &pitch);
+   if (r != DFB_OK)
+     return 0;
+
+   if (pitch != (sw * 4))
+     {
+       /* XXX TODO: support other pixel formats. */
+       fprintf(stderr,
+               "ERROR: IDirectFBSurface pitch(%d) is not supported: "
+               "should be %d.\n",
+               pitch, sw * 4);
+       surface->Unlock(surface);
+       return 0;
+     }
+
+   image->cache_entry.w = sw;
+   image->cache_entry.h = sh;
+   image->image.data = pixels;
+   return 1;
+}
+
+typedef void (*_cb_for_each_cutout_t)(IDirectFBSurface *surface, RGBA_Draw_Context *dc, const DFBRegion *region, void *data);
+static void
+_dfb_surface_for_each_cutout(IDirectFBSurface *surface, RGBA_Draw_Context *dc, _cb_for_each_cutout_t cb, void *data)
+{
+   Cutout_Rects *rects;
+   int i;
+
+   rects = evas_common_draw_context_apply_cutouts(dc);
+   for (i = 0; i < rects->active; ++i)
+     {
+       Cutout_Rect *r;
+       DFBRegion cr;
+
+       r = rects->rects + i;
+
+       cr.x1 = r->x;
+       cr.y1 = r->y;
+       cr.x2 = r->x + r->w - 1;
+       cr.y2 = r->y + r->h - 1;
+       surface->SetClip(surface, &cr);
+       cb(surface, dc, &cr, data);
+     }
+   evas_common_draw_context_apply_clear_cutouts(rects);
+}
+
+static void
+_dfb_rect_set(DFBRectangle *r, int x, int y, int w, int h)
+{
+   r->x = x;
+   r->y = y;
+   r->w = w;
+   r->h = h;
+}
+
+
+/***********************************************************************
+ * Image Cache
+ **********************************************************************/
+static Engine_Image_Entry *
+evas_cache_image_dfb_alloc(void)
+{
+   DirectFB_Engine_Image_Entry *deie;
+
+   deie = calloc(1, sizeof (DirectFB_Engine_Image_Entry));
+
+   return (Engine_Image_Entry *)deie;
+}
+
+static void
+evas_cache_image_dfb_delete(Engine_Image_Entry *eie)
+{
+   free(eie);
+}
+
+static int
+evas_cache_image_dfb_constructor(Engine_Image_Entry *eie, void *data)
+{
+   DirectFB_Engine_Image_Entry *deie = (DirectFB_Engine_Image_Entry *)eie;
+   Render_Engine *re = data;
+   IDirectFBSurface *s;
+   RGBA_Image *im;
+
+   im = (RGBA_Image *)eie->src;
+   if (!im)
+     return 0;
+
+   evas_cache_image_load_data(&im->cache_entry);
+   if (!im->image.data)
+     return 0;
+
+   s = _dfb_surface_from_data(re->spec->dfb, eie->w, eie->h, im->image.data);
+   if (!s)
+     return -1;
+
+   deie->surface = s;
+   deie->flags.engine_surface = 0;
+
+   return 0;
+}
+
+static void
+evas_cache_image_dfb_destructor(Engine_Image_Entry *eie)
+{
+   DirectFB_Engine_Image_Entry *deie = (DirectFB_Engine_Image_Entry *)eie;
+
+   if (!deie->flags.engine_surface)
+     _dfb_surface_free(deie->surface);
+   deie->surface = NULL;
+}
+
+/* note: dst have some properties set, like desired size (w, h) */
+static int
+_cache_image_copy(Engine_Image_Entry *dst, const Engine_Image_Entry *src)
+{
+   DirectFB_Engine_Image_Entry *dst_deie;
+   const DirectFB_Engine_Image_Entry *src_deie;
+   IDirectFBSurface *s;
+   RGBA_Image *im;
+
+   dst_deie = (DirectFB_Engine_Image_Entry *)dst;
+   src_deie = (const DirectFB_Engine_Image_Entry *)src;
+   im = (RGBA_Image *)dst->src;
+   s = _dfb_surface_from_data(dfb, dst->w, dst->h, im->image.data);
+   if (!s)
+     return -1;
+
+   dst_deie->surface = s;
+   dst_deie->flags.engine_surface = 0;
+
+   return 0;
+}
+
+static int
+evas_cache_image_dfb_dirty(Engine_Image_Entry *dst, const Engine_Image_Entry *src)
+{
+   return _cache_image_copy(dst, src);
+}
+
+static void
+evas_cache_image_dfb_dirty_region(Engine_Image_Entry *eim, int x, int y, int w, int h)
+{
+   RGBA_Image *im;
+
+   im = (RGBA_Image *)eim->src;
+   im->flags |= RGBA_IMAGE_IS_DIRTY;
+}
+
+static int
+evas_cache_image_dfb_update_data(Engine_Image_Entry *dst, void *engine_data)
+{
+   DirectFB_Engine_Image_Entry *deie = (DirectFB_Engine_Image_Entry *)dst;
+   IDirectFBSurface *s = engine_data;
+   Image_Entry *ie;
+   RGBA_Image *im;
+
+   ie = dst->src;
+   im = (RGBA_Image *)ie;
+
+   if (s)
+     {
+       deie->surface = s;
+
+       /* XXX why size is required here? */
+       s->GetSize(s, &dst->w, &dst->h);
+
+        if (im)
+          {
+             im->image.data = NULL; /* IDirectFBSurface requires lock */
+             im->image.no_free = 1;
+             ie->w = dst->w;
+            ie->h = dst->h;
+            _image_autoset_alpha(deie);
+          }
+     }
+   else
+     {
+       _dfb_surface_free(deie->surface);
+       s = _dfb_surface_from_data(dfb, dst->w, dst->h, im->image.data);
+       deie->surface = s;
+     }
+
+   return 0;
+}
+
+static int
+evas_cache_image_dfb_size_set(Engine_Image_Entry *dst, const Engine_Image_Entry *src)
+{
+   return _cache_image_copy(dst, src);
+}
+
+static void
+evas_cache_image_dfb_load(Engine_Image_Entry *eim, const Image_Entry *ie)
+{
+   DirectFB_Engine_Image_Entry *deie = (DirectFB_Engine_Image_Entry *)eim;
+   IDirectFBSurface *s;
+   const RGBA_Image *im;
+
+   if (deie->surface)
+     return;
+
+   im = (const RGBA_Image *)ie;
+   s = _dfb_surface_from_data(dfb, eim->w, eim->h, im->image.data);
+   deie->surface = s;
+}
+
+static int
+evas_cache_image_dfb_mem_size_get(Engine_Image_Entry *eie)
+{
+   DirectFB_Engine_Image_Entry *deie = (DirectFB_Engine_Image_Entry *)eie;
+   DFBResult r;
+   int size, w, h;
+
+   if (!deie->surface)
+     return 0;
+
+   size = sizeof(*deie->surface);
+
+   r = deie->surface->GetSize(deie->surface, &w, &h);
+   if (r != DFB_OK)
+     {
+       fprintf(stderr, "ERROR: Could not get surface size: %s\n",
+               DirectFBErrorString(r));
+       return size;
+     }
+
+   size += w * h * 4; // XXX get correct surface size using pixelformat
+
+   return size;
+}
+
+#ifdef DFB_DEBUG_IMAGE
+static void
+evas_cache_image_dfb_debug(const char *context, Engine_Image_Entry* eie)
+{
+   DirectFB_Engine_Image_Entry *eim = (DirectFB_Engine_Image_Entry *)eie;
+
+   fprintf(stderr, "*** %s image (%p) ***\n", context, eim);
+   if (eim)
+     {
+        fprintf(stderr,
+               "* W: %d\n"
+               "* H: %d\n"
+               "* R: %d\n"
+               "* Key: %s\n"
+               "* DFB Surface: %p\n",
+               eie->w, eie->h, eie->references, eie->cache_key, eim->surface);
+
+        if (eie->src)
+          fprintf(stderr,
+                 "* Pixels: %p\n", ((RGBA_Image*) eie->src)->image.data);
+     }
+   fputs("*** ***\n", stderr);
+}
+#endif
+
+static const Evas_Cache_Engine_Image_Func _dfb_cache_engine_image_cb = {
+  NULL /* key */,
+  evas_cache_image_dfb_alloc /* alloc */,
+  evas_cache_image_dfb_delete /* dealloc */,
+  evas_cache_image_dfb_constructor /* constructor */,
+  evas_cache_image_dfb_destructor /* destructor */,
+  evas_cache_image_dfb_dirty_region /* dirty_region */,
+  evas_cache_image_dfb_dirty /* dirty */,
+  evas_cache_image_dfb_size_set /* size_set */,
+  evas_cache_image_dfb_update_data /* update_data */,
+  evas_cache_image_dfb_load /* load */,
+  evas_cache_image_dfb_mem_size_get /* mem_size_get */,
+#ifdef DFB_DEBUG_IMAGE  /* debug */
+  evas_cache_image_dfb_debug
+#else
+  NULL
+#endif
+};
+
+
+/***********************************************************************
+ * Evas Engine
+ **********************************************************************/
+static void *
+evas_engine_dfb_info(Evas* e)
+{
+   Evas_Engine_Info_DirectFB *info;
+
+   info = calloc(1, sizeof(Evas_Engine_Info_DirectFB));
+   if (!info)
+     return NULL;
+
+   info->magic.magic = rand();
+
+   return info;
+}
+
+static void
+evas_engine_dfb_info_free(Evas *e, void *in)
+{
+   Evas_Engine_Info_DirectFB *info = in;
+
+   free(info);
+}
+
+static Evas_Bool
+_is_dfb_data_ok(IDirectFB *idfb, IDirectFBSurface *surface, int w, int h)
+{
+   DFBResult r;
+   int sw, sh;
+
+   if (!idfb)
+     {
+       fputs("ERROR: missing IDirectFB\n", stderr);
+       return 0;
+     }
+   dfb = idfb;
+
+   if (!surface)
+     {
+       fputs("ERROR: missing IDirectFBSurface\n", stderr);
+       return 0;
+     }
+
+   r = surface->GetSize(surface, &sw, &sh);
+   if (r != DFB_OK)
+     {
+       fprintf(stderr, "ERROR: could not get surface %p size: %s\n",
+               surface, DirectFBErrorString(r));
+       return 0;
+     }
+
+   if ((w > sw) || (h > sh))
+     {
+       fprintf(stderr,
+               "ERROR: requested size is larger than surface: %dx%d > %dx%d\n",
+               w, h, sw, sh);
+       return 0;
+     }
+   else if ((w <= 0) || (h <= 0))
+     {
+       w = sw;
+       h = sh;
+     }
+
+   return 1;
+}
+
+static void
+_evas_common_init(void)
+{
+   evas_common_cpu_init();
+   evas_common_blend_init();
+   evas_common_image_init();
+   evas_common_convert_init();
+   evas_common_scale_init();
+   evas_common_rectangle_init();
+   evas_common_gradient_init();
+   evas_common_polygon_init();
+   evas_common_line_init();
+   evas_common_font_init();
+   evas_common_draw_init();
+   evas_common_tilebuf_init();
+}
+
+static int
+evas_engine_dfb_output_reconfigure(Render_Engine *re, int w, int h)
+{
+   if (re->screen_image)
+     evas_cache_engine_image_drop(&re->screen_image->cache_entry);
+
+   if (re->tb)
+     evas_common_tilebuf_free(re->tb);
+
+   re->tb = evas_common_tilebuf_new(w, h);
+   if (!re->tb)
+     {
+       fputs("ERROR: could not allocate tile buffer.\n", stderr);
+       goto failed_tilebuf;
+     }
+   evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+
+   /* We create a "fake" RGBA_Image which points to the IDirectFB surface.
+    * Each access to that surface is wrapped in Lock / Unlock calls whenever
+    * the data is manipulated directly.
+    */
+   re->screen_image = (DirectFB_Engine_Image_Entry *)
+     evas_cache_engine_image_engine(re->cache, re->spec->surface);
+   if (!re->screen_image)
+     {
+       fputs("ERROR: RGBA_Image allocation from DFB failed\n", stderr);
+       goto failed_image;
+     }
+   re->screen_image->flags.engine_surface = 1;
+
+   _image_autoset_alpha(re->screen_image);
+   _image_clear(re->screen_image, 0, 0, w, h);
+
+   return 1;
+
+ failed_image:
+   evas_common_tilebuf_free(re->tb);
+   re->tb = NULL;
+ failed_tilebuf:
+   re->screen_image = NULL;
+   fputs("ERROR: Evas DirectFB reconfigure failed\n", stderr);
+   return 0;
+}
+
+static void *
+_dfb_output_setup(int w, int h, const struct Evas_Engine_DirectFB_Spec *spec)
+{
+   Render_Engine *re;
+
+   if (!_is_dfb_data_ok(spec->dfb, spec->surface, w, h))
+     goto fatal;
+
+   _evas_common_init();
+
+   re = calloc(1, sizeof(Render_Engine));
+   if (!re)
+     {
+       perror("calloc");
+       goto fatal;
+     }
+   re->dfb = spec->dfb;
+   re->spec = spec;
+   re->cache = evas_cache_engine_image_init(&_dfb_cache_engine_image_cb,
+                                           evas_common_image_cache_get());
+   if (!re->cache)
+     {
+       fputs("ERROR: Evas_Cache_Engine_Image allocation failed!\n", stderr);
+       goto fatal_after_engine;
+     }
+
+   if (!evas_engine_dfb_output_reconfigure(re, w, h))
+     {
+       fputs("ERROR: Could not reconfigure evas engine.\n", stderr);
+       goto fatal_after_reconfigure;
+     }
+
+   _dfb_blit_accel_caps_print(spec->surface, NULL);
+
+   return re;
+
+
+ fatal_after_reconfigure:
+   evas_cache_engine_image_shutdown(re->cache);
+ fatal_after_engine:
+   free(re);
+ fatal:
+   fputs("FATAL: unable to continue, abort()!\n", stderr);
+   abort();
+   return NULL;
+}
+
+static void
+evas_engine_dfb_setup(Evas *e, void *in)
+{
+   Evas_Engine_Info_DirectFB *info = in;
+
+   if (!e->engine.data.output)
+     e->engine.data.output = _dfb_output_setup(e->output.w, e->output.h,
+                                              &info->info);
+   // XXX TODO: else reconfigure existing...
+
+   if (!e->engine.data.output)
+     return;
+
+   if (!e->engine.data.context)
+     e->engine.data.context =
+       e->engine.func->context_new(e->engine.data.output);
+}
+
+static void
+evas_engine_dfb_output_free(void *data)
+{
+   Render_Engine *re = data;
+
+   if (!re)
+     return;
+
+   if (re->cache)
+     evas_cache_engine_image_shutdown(re->cache);
+
+   evas_common_tilebuf_free(re->tb);
+   if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
+   free(re);
+
+   evas_common_font_shutdown();
+   evas_common_image_shutdown();
+}
+
+static void
+evas_engine_dfb_output_resize(void *data, int w, int h)
+{
+   if (!evas_engine_dfb_output_reconfigure(data, w, h))
+     fputs("ERROR: failed to resize DirectFB evas\n", stderr);
+}
+
+static void
+evas_engine_dfb_output_tile_size_set(void *data, int w, int h)
+{
+   Render_Engine *re = data;
+
+   evas_common_tilebuf_set_tile_size(re->tb, w, h);
+}
+
+static void
+evas_engine_dfb_output_redraws_rect_add(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re = data;
+
+   evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
+}
+
+static void
+evas_engine_dfb_output_redraws_rect_del(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re = data;
+
+   evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
+}
+
+static void
+evas_engine_dfb_output_redraws_clear(void *data)
+{
+   Render_Engine *re = data;
+
+   evas_common_tilebuf_clear(re->tb);
+}
+
+static void *
+evas_engine_dfb_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch)
+{
+   Render_Engine *re = data;
+   Tilebuf_Rect *tb_rect;
+
+   if (re->end)
+     {
+       re->end = 0;
+       return NULL;
+     }
+   if (!re->rects)
+     {
+       re->rects = evas_common_tilebuf_get_render_rects(re->tb);
+       re->cur_rect = (Evas_Object_List *) re->rects;
+     }
+   if (!re->cur_rect)
+      return NULL;
+
+   tb_rect = (Tilebuf_Rect*) re->cur_rect;
+   *cx = *x = tb_rect->x;
+   *cy = *y = tb_rect->y;
+   *cw = *w = tb_rect->w;
+   *ch = *h = tb_rect->h;
+   re->cur_rect = re->cur_rect->next;
+   if (!re->cur_rect)
+     {
+       evas_common_tilebuf_free_render_rects(re->rects);
+       re->rects = NULL;
+       re->end = 1;
+     }
+
+   _image_clear(re->screen_image, *x, *y, *w, *h );
+
+   return re->screen_image->surface;
+}
+
+static void
+evas_engine_dfb_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
+{
+   Render_Engine *re = data;
+   DFBRegion *r;
+
+   if (re->update_regions_count >= re->update_regions_limit)
+     {
+       void *tmp;
+
+       re->update_regions_limit += 16;
+
+       tmp = realloc(re->update_regions,
+                     sizeof(DFBRegion) * re->update_regions_limit);
+       if (!tmp)
+         {
+            perror("realloc");
+            return;
+         }
+       re->update_regions = tmp;
+     }
+
+   r = re->update_regions + re->update_regions_count;
+   re->update_regions_count++;
+
+   r->x1 = x;
+   r->y1 = y;
+   r->x2 = x + w - 1;
+   r->y2 = y + h - 1;
+}
+
+static void
+evas_engine_dfb_output_flush(void *data)
+{
+   Render_Engine *re = data;
+   IDirectFBSurface *s = re->screen_image->surface;
+   DFBRegion *r, *r_end;
+
+   r = re->update_regions;
+   r_end = re->update_regions + re->update_regions_count;
+
+#ifdef DFB_UPDATE_INDIVIDUAL_RECTS
+   for (; r < r_end; r++)
+     s->Flip(s, r, DFB_FLIP_FLAGS);
+#else
+   DFBRegion bb;
+
+   bb.x1 = bb.y1 = 10000;
+   bb.x2 = bb.y2 = 0;
+   for (; r < r_end; r++)
+     {
+       if (bb.x1 > r->x1)
+         bb.x1 = r->x1;
+       if (bb.y1 > r->y1)
+         bb.y1 = r->y1;
+
+       if (bb.x2 < r->x2)
+         bb.x2 = r->x2;
+       if (bb.y2 < r->y2)
+         bb.y2 = r->y2;
+     }
+
+   s->Flip(s, &bb, DFB_FLIP_FLAGS);
+#endif
+
+   re->update_regions_count = 0;
+}
+
+static void
+evas_engine_dfb_output_idle_flush(void *data)
+{
+   Render_Engine *re = data;
+
+   if (re->update_regions_count != 0)
+     fputs("ERROR: update_regions_count not 0 as it should be!\n", stderr);
+
+   free(re->update_regions);
+   re->update_regions_count = 0;
+   re->update_regions_limit = 0;
+   re->update_regions = NULL;
+}
+
+/* HACK!!! -- KLUDGE!!!
+ *
+ * This should really use IDirectFBFont and IDirectFBSurface::DrawString(),
+ * but to be edje-compatible IDirectFBFont::CreateFont() should be able to
+ * load fonts from non-files, which it does not.
+ *
+ * Try to find a way to create own IDirectFBFont in future and load from
+ * memory.
+ */
+static void
+evas_engine_dfb_font_draw(void *data, void *context, void *surface, void *font, int x, int y, int w, int h, int ow, int oh, const char *text)
+{
+   Render_Engine *re = data;
+   RGBA_Image *im;
+   IDirectFBSurface *screen = surface;
+
+   im = (RGBA_Image *)re->screen_image->cache_entry.src;
+
+   if (!_dfb_lock_and_sync_image(screen, im, DSLF_READ | DSLF_WRITE))
+     return;
+
+   evas_common_font_draw(im, context, font, x, y, text);
+   evas_common_cpu_end_opt();
+
+   im->image.data = NULL;
+
+   screen->Unlock(screen);
+}
+
+
+static void
+_cb_draw_line(IDirectFBSurface *surface, RGBA_Draw_Context *dc, const DFBRegion *region, void *data)
+{
+   const Evas_Rectangle *r = data;
+
+   surface->DrawLine(surface, r->x, r->y, r->w, r->h); /* x2, y2 really */
+}
+
+static void
+evas_engine_dfb_line_draw(void *data, void *context, void *surface, int x1, int y1, int x2, int y2)
+{
+   IDirectFBSurface *screen = surface;
+   Evas_Rectangle r;
+
+   if (!_dfb_surface_set_color_from_context(screen, context))
+     return;
+
+   _rect_set(&r, x1, y1, x2, y2); /* x2, y2 (ab)used as w, h */
+   _dfb_surface_for_each_cutout(screen, context, _cb_draw_line, &r);
+}
+
+#ifndef DFB_USE_EVAS_RECT_DRAW
+static void
+_cb_draw_rectangle(IDirectFBSurface *surface, RGBA_Draw_Context *dc, const DFBRegion *region, void *data)
+{
+   const Evas_Rectangle *r = data;
+
+   surface->FillRectangle(surface, r->x, r->y, r->w, r->h);
+}
+
+static void
+evas_engine_dfb_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h)
+{
+   IDirectFBSurface *screen = surface;
+   Evas_Rectangle r;
+
+   if (!_dfb_surface_set_color_from_context(screen, context))
+     return;
+
+   _rect_set(&r, x, y, w, h);
+   _dfb_surface_for_each_cutout(screen, context, _cb_draw_rectangle, &r);
+}
+#else
+static void
+evas_engine_dfb_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h)
+{
+   Render_Engine *re = data;
+   IDirectFBSurface *screen = surface;
+   RGBA_Image *dst;
+
+   dst = (RGBA_Image *)re->screen_image->cache_entry.src;
+   if (!_dfb_lock_and_sync_image(screen, dst, DSLF_READ | DSLF_WRITE))
+     return;
+
+   evas_common_rectangle_draw(dst, context, x, y, w, h);
+   evas_common_cpu_end_opt();
+
+   dst->image.data = NULL;
+
+   screen->Unlock(screen);
+}
+#endif
+
+#ifndef DFB_USE_EVAS_POLYGON_DRAW
+static void
+evas_engine_dfb_polygon_draw(void *data, void *context, void *surface, void *polygon)
+{
+   _dfb_polygon_draw(surface, context, polygon);
+}
+#else
+static void
+evas_engine_dfb_polygon_draw(void *data, void *context, void *surface, void *polygon)
+{
+   Render_Engine *re = data;
+   IDirectFBSurface *screen = surface;
+   RGBA_Image *dst;
+
+   dst = (RGBA_Image *)re->screen_image->cache_entry.src;
+   if (!_dfb_lock_and_sync_image(screen, dst, DSLF_READ | DSLF_WRITE))
+     return;
+
+   evas_common_polygon_draw(dst, context, polygon);
+   evas_common_cpu_end_opt();
+
+   dst->image.data = NULL;
+
+   screen->Unlock(screen);
+}
+#endif
+
+static void
+evas_engine_dfb_gradient_draw(void *data, void *context, void *surface, void *gradient, int x, int y, int w, int h)
+{
+   Render_Engine *re = data;
+   RGBA_Image *dst, *src;
+   IDirectFBSurface *screen = surface;
+
+   dst = (RGBA_Image *)re->screen_image->cache_entry.src;
+   if (!_dfb_lock_and_sync_image(screen, dst, DSLF_READ | DSLF_WRITE))
+     return;
+
+   evas_common_gradient_draw(dst, context, x, y, w, h, gradient);
+   evas_common_cpu_end_opt();
+
+   dst->image.data = NULL;
+
+   screen->Unlock(screen);
+
+   return;
+}
+
+/** Image Object *******************************************************/
+static void *
+evas_engine_dfb_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo)
+{
+   Render_Engine *re = data;
+
+   *error = 0;
+   return evas_cache_engine_image_request(re->cache, file, key, lo,
+                                         data, error);
+}
+
+static int
+evas_engine_dfb_image_alpha_get(void *data, void *image)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+   Image_Entry *ie;
+   RGBA_Image *im;
+
+   if (!eim) return 1;
+   ie = eim->cache_entry.src;
+   im = (RGBA_Image *)ie;
+   switch (ie->space)
+     {
+      case EVAS_COLORSPACE_ARGB8888:
+        if (ie->flags.alpha) return 1;
+      default:
+        break;
+     }
+   return 0;
+}
+
+static void
+evas_engine_dfb_image_size_get(void *data, void *image, int *w, int *h)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+   Image_Entry *ie;
+
+   ie = eim->cache_entry.src;
+   if (w) *w = ie->w;
+   if (h) *h = ie->h;
+}
+
+static int
+evas_engine_dfb_image_colorspace_get(void *data, void *image)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+
+   if (!eim) return EVAS_COLORSPACE_ARGB8888;
+   return eim->cache_entry.src->space;
+}
+
+static void
+evas_engine_dfb_image_colorspace_set(void *data, void *image, int cspace)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+
+   if (!eim) return;
+   if (eim->cache_entry.src->space == cspace) return;
+
+   evas_cache_engine_image_colorspace(&eim->cache_entry, cspace, data);
+}
+
+static void *
+evas_engine_dfb_image_new_from_copied_data(void *data, int w, int h, DATA32* image_data, int alpha, int cspace)
+{
+   Render_Engine *re = data;
+
+   return evas_cache_engine_image_copied_data(re->cache, w, h, image_data,
+                                             alpha, cspace, NULL);
+}
+
+static void *
+evas_engine_dfb_image_new_from_data(void *data, int w, int h, DATA32* image_data, int alpha, int cspace)
+{
+   Render_Engine *re = data;
+
+   return evas_cache_engine_image_data(re->cache, w, h, image_data,
+                                      alpha, cspace, NULL);
+}
+
+static void
+evas_engine_dfb_image_free(void *data, void *image)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+
+   evas_cache_engine_image_drop(&eim->cache_entry);
+}
+
+static void *
+evas_engine_dfb_image_size_set(void *data, void *image, int w, int h)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+
+   return evas_cache_engine_image_size_set(&eim->cache_entry, w, h);
+}
+
+static void *
+evas_engine_dfb_image_dirty_region(void *data, void *image, int x, int y, int w, int h)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+
+   return evas_cache_engine_image_dirty(&eim->cache_entry, x, y, w, h);
+}
+
+static void *
+evas_engine_dfb_image_data_get(void *data, void *image, int to_write, DATA32** image_data)
+{
+   DirectFB_Engine_Image_Entry *deie = image;
+   Engine_Image_Entry *ce;
+   Image_Entry *ie;
+   RGBA_Image *im;
+
+   if (!deie)
+     {
+        *image_data = NULL;
+        return NULL;
+     }
+
+   ce = (Engine_Image_Entry *)deie;
+   ie = ce->src;
+   im = (RGBA_Image *)ie;
+
+   switch (ie->space)
+     {
+     case EVAS_COLORSPACE_ARGB8888:
+       {
+         DFBResult r;
+         IDirectFBSurface *s;
+         void *pixels;
+         int pitch;
+
+         if (to_write)
+           deie = (DirectFB_Engine_Image_Entry *)
+             evas_cache_engine_image_dirty(ce, 0, 0, ie->w, ie->h);
+
+         evas_cache_engine_image_load_data(ce);
+
+         ce = (Engine_Image_Entry *)deie;
+         ie = ce->src;
+         im = (RGBA_Image *)ie;
+         s = deie->surface;
+
+         if (to_write)
+           {
+              r = s->Lock(s, DSLF_WRITE, &pixels, &pitch);
+              if (r != DFB_OK)
+                goto error;
+              deie->flags.is_locked = 1;
+           }
+         else
+           {
+              r = s->Lock(s, DSLF_READ, &pixels, &pitch);
+              if (r != DFB_OK)
+                goto error;
+              s->Unlock(s);
+           }
+
+         *image_data = pixels;
+         im->image.data = pixels; /* remember for _put() */
+         break;
+
+       error:
+         fprintf(stderr, "ERROR: could not lock surface %p: %s\n",
+                 s, DirectFBErrorString(r));
+         *image_data = NULL;
+         break;
+       }
+     case EVAS_COLORSPACE_YCBCR422P709_PL:
+     case EVAS_COLORSPACE_YCBCR422P601_PL:
+       /* XXX untested */
+        *image_data = im->cs.data;
+        break;
+     default:
+        abort();
+        break;
+     }
+   return deie;
+}
+
+static void *
+evas_engine_dfb_image_data_put(void *data, void *image, DATA32* image_data)
+{
+   DirectFB_Engine_Image_Entry *deie = image;
+   Render_Engine *re = data;
+   Engine_Image_Entry *ce;
+   Image_Entry *ie;
+   RGBA_Image *im;
+
+   if (!deie) return NULL;
+
+   ce = (Engine_Image_Entry *)deie;
+   ie = ce->src;
+   im = (RGBA_Image*)ie;
+
+   switch (ie->space)
+     {
+     case EVAS_COLORSPACE_ARGB8888:
+       if (image_data == im->image.data)
+         {
+            if (deie->flags.is_locked)
+              {
+                 deie->surface->Unlock(deie->surface);
+                 deie->flags.is_locked = 0;
+              }
+         }
+       else
+          {
+            int alpha, cspace;
+
+            alpha = func.image_alpha_get(re, deie);
+            cspace = func.image_colorspace_get(re, deie);
+
+             evas_cache_engine_image_drop(ce);
+             deie = (DirectFB_Engine_Image_Entry *)
+              evas_cache_engine_image_data(re->cache, ce->w, ce->h,
+                                           image_data, alpha, cspace, data);
+          }
+        break;
+     case EVAS_COLORSPACE_YCBCR422P601_PL:
+     case EVAS_COLORSPACE_YCBCR422P709_PL:
+       /* XXX untested */
+        if (image_data != im->cs.data)
+          {
+             if (im->cs.data)
+               if (!im->cs.no_free)
+                 free(im->cs.data);
+             im->cs.data = image_data;
+             evas_common_image_colorspace_dirty(im);
+          }
+        break;
+     default:
+        abort();
+        break;
+     }
+   return deie;
+}
+
+static void *
+evas_engine_dfb_image_alpha_set(void *data, void *image, int has_alpha)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+   Engine_Image_Entry *ce;
+   Image_Entry *ie;
+   RGBA_Image *im;
+
+   if (!eim) return NULL;
+
+   ce = &eim->cache_entry;
+   ie = ce->src;
+   im = (RGBA_Image*)ie;
+
+   if (ie->space != EVAS_COLORSPACE_ARGB8888)
+     {
+        ie->flags.alpha = 0;
+        return eim;
+     }
+
+   eim = (DirectFB_Engine_Image_Entry *)
+     evas_cache_engine_image_dirty(ce, 0, 0, ce->w, ce->h);
+
+   ie->flags.alpha = !!has_alpha;
+   return eim;
+}
+
+struct _for_each_cutout_image
+{
+   IDirectFBSurface *image;
+   DFBRectangle src, dst;
+};
+
+static void
+_cb_draw_image_unscaled(IDirectFBSurface *surface, RGBA_Draw_Context *dc, const DFBRegion *region, void *data)
+{
+   const struct _for_each_cutout_image *p = data;
+
+   surface->Blit(surface, p->image, &p->src, p->dst.x, p->dst.y);
+}
+
+static void
+_cb_draw_image_scaled(IDirectFBSurface *surface, RGBA_Draw_Context *dc, const DFBRegion *region, void *data)
+{
+   const struct _for_each_cutout_image *p = data;
+
+   surface->StretchBlit(surface, p->image, &p->src, &p->dst);
+}
+
+#ifndef DFB_USE_EVAS_IMAGE_DRAW
+static void
+evas_engine_dfb_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth)
+{
+   Render_Engine *re = data;
+   IDirectFBSurface *screen = surface;
+   DirectFB_Engine_Image_Entry *deie = image;
+   struct _for_each_cutout_image p;
+   _cb_for_each_cutout_t cb;
+
+   if (deie->cache_entry.src->space == EVAS_COLORSPACE_ARGB8888)
+     evas_cache_engine_image_load_data(&deie->cache_entry);
+
+   evas_common_image_colorspace_normalize((RGBA_Image *)deie->cache_entry.src);
+
+   _dfb_surface_set_blit_params(re->screen_image, deie, context);
+
+   _dfb_rect_set(&p.src, src_x, src_y, src_w, src_h);
+   _dfb_rect_set(&p.dst, dst_x, dst_y, dst_w, dst_h);
+   p.image = deie->surface;
+
+   if ((src_w == dst_w) && (src_h == dst_h))
+     cb = _cb_draw_image_unscaled;
+   else
+     cb = _cb_draw_image_scaled;
+
+   _dfb_blit_accel_caps_print(screen, deie->surface);
+   _dfb_surface_for_each_cutout(screen, context, cb, &p);
+}
+#else /* DFB_USE_EVAS_IMAGE_DRAW */
+static void
+evas_engine_dfb_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth)
+{
+   DirectFB_Engine_Image_Entry *deie = image;
+   Render_Engine *re = data;
+   RGBA_Image *dst, *src;
+   IDirectFBSurface *screen = surface;
+
+   if (deie->cache_entry.src->space == EVAS_COLORSPACE_ARGB8888)
+     evas_cache_engine_image_load_data(&deie->cache_entry);
+
+   evas_common_image_colorspace_normalize((RGBA_Image *)deie->cache_entry.src);
+
+   dst = (RGBA_Image *)re->screen_image->cache_entry.src;
+   if (!_dfb_lock_and_sync_image(screen, dst, DSLF_READ | DSLF_WRITE))
+     return;
+
+   src = (RGBA_Image *)deie->cache_entry.src;
+   if (!_dfb_lock_and_sync_image(deie->surface, src, DSLF_READ))
+     goto error_src;
+
+   if (smooth)
+     evas_common_scale_rgba_in_to_out_clip_smooth(src, dst, context,
+                                                 src_x, src_y, src_w, src_h,
+                                                 dst_x, dst_y, dst_w, dst_h);
+   else
+     evas_common_scale_rgba_in_to_out_clip_sample(src, dst, context,
+                                                 src_x, src_y, src_w, src_h,
+                                                 dst_x, dst_y, dst_w, dst_h);
+   evas_common_cpu_end_opt();
+
+   dst->image.data = NULL;
+
+   screen->Unlock(screen);
+   deie->surface->Unlock(deie->surface);
+
+   return;
+
+ error_src:
+   screen->Unlock(screen);
+}
+#endif
+
+static void
+evas_engine_dfb_image_cache_flush(void *data)
+{
+   Render_Engine *re = data;
+   int size;
+
+   size = evas_cache_engine_image_get(re->cache);
+   evas_cache_engine_image_set(re->cache, 0);
+   evas_cache_engine_image_set(re->cache, size);
+}
+
+static void
+evas_engine_dfb_image_cache_set(void *data, int bytes)
+{
+   Render_Engine *re = data;
+
+   evas_cache_engine_image_set(re->cache, bytes);
+}
+
+static int
+evas_engine_dfb_image_cache_get(void *data)
+{
+   Render_Engine *re = data;
+
+   return evas_cache_engine_image_get(re->cache);
+}
+
+static char *
+evas_engine_dfb_image_comment_get(void *data, void *image, char *key)
+{
+   DirectFB_Engine_Image_Entry *eim = image;
+   RGBA_Image *im;
+
+   if (!eim) return NULL;
+   im = (RGBA_Image *)eim->cache_entry.src;
+
+   return im->info.comment;
+}
+
+EAPI int
+module_open(Evas_Module *em)
+{
+   if (!em) return 0;
+   /* get whatever engine module we inherit from */
+   if (!_evas_module_engine_inherit(&parent_func, "software_generic")) return 0;
+   /* store it for later use */
+   func = parent_func;
+   /* now to override methods */
+#define ORD(f) EVAS_API_OVERRIDE(f, &func, evas_engine_dfb_)
+   ORD(info);
+   ORD(info_free);
+   ORD(setup);
+   ORD(output_free);
+   ORD(output_resize);
+   ORD(output_tile_size_set);
+   ORD(output_redraws_rect_add);
+   ORD(output_redraws_rect_del);
+   ORD(output_redraws_clear);
+   ORD(output_redraws_next_update_get);
+   ORD(output_redraws_next_update_push);
+   ORD(output_flush);
+   ORD(output_idle_flush);
+   ORD(image_load);
+   ORD(image_new_from_data);
+   ORD(image_new_from_copied_data);
+   ORD(image_colorspace_set);
+   ORD(image_colorspace_get);
+   ORD(image_free);
+   ORD(image_size_set);
+   ORD(image_size_get);
+   ORD(image_dirty_region);
+   ORD(image_data_get);
+   ORD(image_data_put);
+   ORD(image_alpha_set);
+   ORD(image_alpha_get);
+   ORD(image_draw);
+   ORD(image_comment_get);
+   ORD(image_cache_flush);
+   ORD(image_cache_set);
+   ORD(image_cache_get);
+   ORD(font_draw);
+   ORD(line_draw);
+   ORD(rectangle_draw);
+   ORD(polygon_draw);
+   ORD(gradient_draw);
+   /* now advertise out own api */
+   em->functions = (void *)(&func);
+   return 1;
+}
+
+EAPI void
+module_close(void)
+{
+}
+
+EAPI Evas_Module_Api evas_modapi =
+{
+   EVAS_MODULE_API_VERSION,
+   EVAS_MODULE_TYPE_ENGINE,
+   "directfb",
+   "ProFUSION embedded systems"
+};
diff --git a/src/modules/engines/directfb/evas_engine.h b/src/modules/engines/directfb/evas_engine.h
new file mode 100644 (file)
index 0000000..28d3964
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef EVAS_ENGINE_DIRECTFB_H
+#define EVAS_ENGINE_DIRECTFB_H
+
+#include "evas_common.h"
+#include "evas_private.h"
+#include "Evas_Engine_DirectFB.h"
+
+typedef struct _DirectFB_Engine_Image_Entry DirectFB_Engine_Image_Entry;
+struct _DirectFB_Engine_Image_Entry
+{
+   Engine_Image_Entry            cache_entry;
+   IDirectFBSurface             *surface;
+
+   struct
+   {
+      Evas_Bool                   engine_surface : 1;
+      Evas_Bool                   is_locked : 1;
+   } flags;
+};
+
+typedef struct _Render_Engine Render_Engine;
+struct _Render_Engine
+{
+   DirectFB_Engine_Image_Entry  *screen_image;
+   const struct Evas_Engine_DirectFB_Spec *spec;
+   IDirectFB                    *dfb;
+
+   Evas_Cache_Engine_Image      *cache;
+
+   Tilebuf                      *tb;
+   Tilebuf_Rect                 *rects;
+   Evas_Object_List             *cur_rect;
+
+   DFBRegion                    *update_regions;
+   unsigned int                  update_regions_count;
+   unsigned int                  update_regions_limit;
+
+   Evas_Bool                     end : 1;
+};
+
+int _dfb_surface_set_color_from_context(IDirectFBSurface *surface, RGBA_Draw_Context *dc);
+void _dfb_polygon_draw(IDirectFBSurface *surface, RGBA_Draw_Context *dc, Evas_Object_List *points);
+
+#endif
diff --git a/src/modules/engines/directfb/polygon.c b/src/modules/engines/directfb/polygon.c
new file mode 100644 (file)
index 0000000..39797a3
--- /dev/null
@@ -0,0 +1,270 @@
+#include <math.h>
+#include "evas_engine.h"
+
+/* Work around bug in DirectFB FillSpans(), but uses twice as much memory */
+#define USE_SPAN_RECTS 1
+
+#define MAX_SPANS 512
+typedef struct _RGBA_Edge RGBA_Edge;
+typedef struct _RGBA_Vertex RGBA_Vertex;
+
+struct _RGBA_Edge
+{
+   double x, dx;
+   int i;
+};
+
+struct _RGBA_Vertex
+{
+   double x, y;
+   int i;
+};
+
+#define POLY_EDGE_DEL(_i)                                               \
+{                                                                       \
+   int _j;                                                              \
+                                                                        \
+   for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++);  \
+   if (_j < num_active_edges)                                           \
+     {                                                                  \
+       num_active_edges--;                                             \
+       memmove(&(edges[_j]), &(edges[_j + 1]),                         \
+               (num_active_edges - _j) * sizeof(RGBA_Edge));           \
+     }                                                                  \
+}
+
+#define POLY_EDGE_ADD(_i, _y)                                           \
+{                                                                       \
+   int _j;                                                              \
+   float _dx;                                                           \
+   RGBA_Vertex *_p, *_q;                                                \
+   if (_i < (n - 1)) _j = _i + 1;                                       \
+   else _j = 0;                                                         \
+   if (point[_i].y < point[_j].y)                                       \
+     {                                                                  \
+       _p = &(point[_i]);                                              \
+       _q = &(point[_j]);                                              \
+     }                                                                  \
+   else                                                                 \
+     {                                                                  \
+       _p = &(point[_j]);                                              \
+       _q = &(point[_i]);                                              \
+     }                                                                  \
+   edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
+   edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
+   edges[num_active_edges].i = _i;                                      \
+   num_active_edges++;                                                  \
+}
+
+static int
+polygon_point_sorter(const void *a, const void *b)
+{
+   RGBA_Vertex *p, *q;
+
+   p = (RGBA_Vertex *)a;
+   q = (RGBA_Vertex *)b;
+   if (p->y <= q->y) return -1;
+   return 1;
+}
+
+static int
+polygon_edge_sorter(const void *a, const void *b)
+{
+   RGBA_Edge *p, *q;
+
+   p = (RGBA_Edge *)a;
+   q = (RGBA_Edge *)b;
+   if (p->x <= q->x) return -1;
+   return 1;
+}
+
+#ifndef USE_SPAN_RECTS
+typedef DFBSpan span_t;
+
+static void
+polygon_span_add(span_t *span, int y, int x, int w)
+{
+   span->x = x;
+   span->w = w;
+}
+
+static void
+polygon_spans_fill(IDirectFBSurface *surface, int y, const span_t *spans, int n_spans)
+{
+   surface->FillSpans(surface, y, spans, n_spans);
+}
+#else /* USE_SPAN_RECTS */
+typedef DFBRectangle span_t;
+
+static void
+polygon_span_add(span_t *span, int y, int x, int w)
+{
+   span->x = x;
+   span->y = y;
+   span->w = w;
+   span->h = 1;
+}
+
+static void
+polygon_spans_fill(IDirectFBSurface *surface, int y, const span_t *spans, int n_spans)
+{
+   surface->FillRectangles(surface, spans, n_spans);
+}
+#endif /* USE_SPAN_RECTS */
+
+
+void
+_dfb_polygon_draw(IDirectFBSurface *surface, RGBA_Draw_Context *dc, Evas_Object_List *points)
+{
+   RGBA_Polygon_Point *pt;
+   RGBA_Vertex        *point;
+   RGBA_Edge          *edges;
+   Evas_Object_List   *l;
+   int                 num_active_edges;
+   int                 n;
+   int                 i, j, k;
+   int                 y0, y1, y;
+   int                 ext_x, ext_y, ext_w, ext_h;
+   int                *sorted_index;
+
+   ext_x = 0;
+   ext_y = 0;
+   surface->GetSize(surface, &ext_w, &ext_h);
+   if (dc->clip.use)
+     {
+       if (dc->clip.x > ext_x)
+         {
+            ext_w += ext_x - dc->clip.x;
+            ext_x = dc->clip.x;
+         }
+       if ((ext_x + ext_w) > (dc->clip.x + dc->clip.w))
+         {
+            ext_w = (dc->clip.x + dc->clip.w) - ext_x;
+         }
+       if (dc->clip.y > ext_y)
+         {
+            ext_h += ext_y - dc->clip.y;
+            ext_y = dc->clip.y;
+         }
+       if ((ext_y + ext_h) > (dc->clip.y + dc->clip.h))
+         {
+            ext_h = (dc->clip.y + dc->clip.h) - ext_y;
+         }
+     }
+   if ((ext_w <= 0) || (ext_h <= 0)) return;
+
+   evas_common_cpu_end_opt();
+
+   if (!_dfb_surface_set_color_from_context(surface, dc))
+     return;
+
+   n = 0; for (l = (Evas_Object_List *)points; l; l = l->next) n++;
+   if (n < 3) return;
+   edges = malloc(sizeof(RGBA_Edge) * n);
+   if (!edges) return;
+   point = malloc(sizeof(RGBA_Vertex) * n);
+   if (!point)
+     {
+       free(edges);
+       return;
+     }
+   sorted_index = malloc(sizeof(int) * n);
+   if (!sorted_index)
+     {
+       free(edges);
+       free(point);
+       return;
+     }
+
+   k = 0;
+   for (l = (Evas_Object_List *)points; l; l = l->next)
+     {
+       pt = (RGBA_Polygon_Point *)l;
+       point[k].x = pt->x;
+       point[k].y = pt->y;
+       point[k].i = k;
+       k++;
+     }
+   qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
+   for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
+   k = 0;
+   for (l = (Evas_Object_List *)points; l; l = l->next)
+     {
+       pt = (RGBA_Polygon_Point *)l;
+       point[k].x = pt->x;
+       point[k].y = pt->y;
+       point[k].i = k;
+       k++;
+     }
+
+   y0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
+   y1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
+
+   k = 0;
+   num_active_edges = 0;
+
+   for (y = y0; y <= y1; y++)
+     {
+       span_t spans[MAX_SPANS];
+       unsigned int n_spans = 0;
+
+       for (; (k < n) && (point[sorted_index[k]].y <= ((double)y + 0.5)); k++)
+         {
+            i = sorted_index[k];
+
+            if (i > 0) j = i - 1;
+            else j = n - 1;
+            if (point[j].y <= ((double)y - 0.5))
+              {
+                 POLY_EDGE_DEL(j)
+              }
+            else if (point[j].y > ((double)y + 0.5))
+              {
+                 POLY_EDGE_ADD(j, y)
+              }
+            if (i < (n - 1)) j = i + 1;
+            else j = 0;
+            if (point[j].y <= ((double)y - 0.5))
+              {
+                 POLY_EDGE_DEL(i)
+              }
+            else if (point[j].y > ((double)y + 0.5))
+              {
+                 POLY_EDGE_ADD(i, y)
+              }
+         }
+
+       qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
+
+       for (j = 0; j < num_active_edges; j += 2)
+         {
+            int x0, x1;
+
+            x0 = ceil(edges[j].x - 0.5);
+            if (j < (num_active_edges - 1))
+              x1 = floor(edges[j + 1].x - 0.5);
+            else
+              x1 = x0;
+            if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
+              {
+                 if (n_spans == MAX_SPANS)
+                   {
+                      polygon_spans_fill(surface, y, spans, n_spans);
+                      n_spans = 0;
+                   }
+
+                 polygon_span_add(spans + n_spans, y, x0, (x1 - x0) + 1);
+                 n_spans++;
+              }
+            edges[j].x += edges[j].dx;
+            edges[j + 1].x += edges[j + 1].dx;
+         }
+
+       if (n_spans)
+         polygon_spans_fill(surface, y, spans, n_spans);
+     }
+
+   free(edges);
+   free(point);
+   free(sorted_index);
+}