[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[E-devel] SDL Engine



Hi,

	I started a SDL engine for evas and would like some feedback. First it's 
working and you will see something with evas_sdl_test. But I have already a 
few questions.
	I wanted to directly manipulate SDL_Surface inside RGBA_Image, but this means 
that for the destruction, I need to call SDL_FreeSurface or I didn't find a 
way to do that using the evas_common API. To handle this case, I implemented 
my own cache mechanism and copy/pasted all functions destroying some 
RGBA_Image. Well that is working, but that's definitely not clean. So I 
extract the cache mechanism and make it an evas API (separate patch in 
evas-data-cache.diff). But this didn't change the problem with evas_common 
function, like module loaders and others need to be copied. I really don't 
know how to handle this case correctly. Perhaps adding some callbacks for 
freeing and creating new image to evas_common_image_init() could be a 
solution to this duplication of code. Did you prefer a separate cache API, or 
should I put it back in the SDL engine ?
	Right now SDL cache is only handling one RGBA_Image with the same 
key/filename at a time. This means that if one RGBA_Image is dirty but still 
referenced, the new one will not be able to evict it. I could fix this by 
storing a list of RGBA_Image per key/filename, but right now the 
evas_sdl_test seems to be correct. Did I need to take care of this kind of 
issue or is it ok this way ?
	In the same idea, what are the purpose of engine_image_border_set, 
engine_image_border_get and engine_image_format_get ? They seem empty in all 
engine I am looking in.
	Now if you tried the test program and hide the SDL output, you will notice 
that the part that didn't change stays black. To solve this, I need to handle 
SDL_ExposeEvent, but I don't really know where. As I understood most events 
are handle in ecore. But X11 backend for example, seems to be aware of this 
kind of issue. Did I need to check for SDL pending event every time 
evas_engine_sdl_output_flush is running ? Or did it exist a better way to do 
that ?

  Cedric
diff -Nru -x CVS e17-main/libs/evas/src/lib/data/evas_cache.c e17-dev/libs/evas/src/lib/data/evas_cache.c
--- e17-main/libs/evas/src/lib/data/evas_cache.c	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/lib/data/evas_cache.c	2006-08-08 18:58:28.000000000 +0200
@@ -0,0 +1,482 @@
+#include <values.h>
+#include "evas_common.h"
+#include "evas_private.h"
+
+#define	EVAS_CACHE_MAGIC	0xDEADBEEF
+
+static int			_evas_cache_empty_necessity	(Evas_Cache* cache, int object_size, int force);
+static void			_evas_cache_remove_object	(Evas_Cache* cache, int position);
+static Evas_Cache_Object*	_evas_cache_lookup		(Evas_Cache* cache, const char* key);
+static int			_evas_cache_lookup_int		(Evas_Cache* cache, const char* key);
+static Evas_Data_Error		_evas_cache_match_size		(Evas_Cache* cache, int adding_size);
+static Evas_Data_Error		_evas_cache_match_count		(Evas_Cache* cache);
+
+/**
+ * @defgroup Evas_Cache Memory pool manipulation functions for fixed size object
+ *
+ */
+
+/**
+ * Build a new Evas_Cache object
+ * @param evict			Function called when an object must be removed from the cache.
+ * @param max_objects_count	Limit the maximum number of objects in the cache (0 means no limit).
+ * @param max_size		Limit the size of the stored object in the cache (0 means no limit).
+ * @return			A pointer to the new allocated cache object
+ * @ingroup Evas_Cache
+ */
+EAPI Evas_Cache*
+evas_cache_init		(void (*evict)(Evas_Cache* cache, const char* key, void* object, int reference), int max_objects_count, int max_size)
+{
+   Evas_Cache*	new_cache = malloc (sizeof (struct _Evas_Cache));
+
+   if (new_cache)
+     {
+	new_cache->magic = EVAS_CACHE_MAGIC;
+
+	new_cache->cache_content = NULL;
+	new_cache->objects = NULL;
+	new_cache->current_objects_limit = 0;
+
+	new_cache->max_size = max_size;
+	new_cache->max_objects_count = max_objects_count;
+
+	new_cache->current_size = 0;
+	new_cache->current_objects_count = 0;
+
+	new_cache->evict = evict;
+     }
+   return new_cache;
+}
+
+/**
+ * Destroy the cache and evict all the object stored in it
+ * @param cache	The cache object to be destroyed
+ * @return	EVAS_DATA_NONE if no error happen during the destruction or the error code corresponding to the encoutered error.
+ * @ingroup Evas_Cache
+ */
+EAPI Evas_Data_Error
+evas_cache_shutdown	(Evas_Cache* cache)
+{
+   Evas_Data_Error	error = EVAS_DATA_NONE;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return EVAS_DATA_NULL;
+
+   error = evas_cache_force_flush (cache);
+   if (error != EVAS_DATA_NONE)
+     return error;
+
+   free (cache);
+   return EVAS_DATA_NONE;
+}
+
+/**
+ * This function search inside the cache an object matching the key and increase the reference to it.
+ * @param cache	The cache we refer to
+ * @param key	The key pointing to the object we whant to get a reference to.
+ * @return	A pointer to the increased reference object or NULL if the object was not found.
+ * @ingroup Evas_Cache
+ */
+EAPI void*
+evas_cache_reference	(Evas_Cache* cache, const char* key)
+{
+   int			i = 0;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return NULL;
+
+   cache->error = EVAS_DATA_NONE;
+
+   i = _evas_cache_lookup_int (cache, key);
+   if (i != -1)
+     {
+	cache->objects[i].requested_time++;
+	cache->objects[i].reference++;
+
+	return cache->objects[i].object;
+     }
+
+   return NULL;
+}
+
+/**
+ * This function push inside the cache a new version of the requested object. If
+ * an object with the same key and still referenced is detected, the insertion
+ * will be aborded.
+ *
+ * The insertion of a new object will result in the call of evict on other
+ * objects (to match constraint on the cache, or because an object with the same
+ * key already exist).
+ *
+ * @param cache		The cache in which we want to insert/update the object.
+ * @param key		The key describing the object.
+ * @param object	The object to be inserted inside the cache.
+ * @param force		Enforce or not the limit set to this cache (maximum number of objects or maximum size).
+ * @return		A pointer to the inserted object.
+ * @ingroup Evas_Cache
+ */
+EAPI void*
+evas_cache_update	(Evas_Cache* cache, const char* key, void* object, int object_size, int force)
+{
+   int			i = 0;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return NULL;
+
+   cache->error = EVAS_DATA_NONE;
+
+   i = _evas_cache_lookup_int (cache, key);
+   if (i != -1)
+     {
+	/* Security: If the object is still referenced somewhere we will refuse to destroy it */
+	if (cache->objects[i].reference > 0)
+	  {
+	     cache->error = EVAS_DATA_CONFLICT;
+	     return NULL;
+	  }
+	_evas_cache_remove_object (cache, i);
+     }
+
+   i = _evas_cache_empty_necessity (cache, object_size, force);
+   if (i == -1)
+     {
+	cache->error = EVAS_DATA_FULL;
+	return NULL;
+     }
+
+   cache->objects[i].object = object;
+   cache->objects[i].object_size = object_size;
+   cache->objects[i].requested_time = 0;
+   cache->objects[i].key = evas_stringshare_add (key);
+   cache->objects[i].reference = 0;
+
+   cache->cache_content = evas_hash_direct_add (cache->cache_content, cache->objects[i].key, i + 1);
+
+   (cache->current_objects_count)++;
+   cache->current_size += object_size;
+
+   return object;
+}
+
+/**
+ * This decrease by one the number of instance of the object pointed by the key. The object will not be removed at this
+ * point, but it could if requested.
+ *
+ * @param cache	The current cache in which we want to dereference the object.
+ * @param key	The key describing the object to dereference.
+ * @return	EVAS_DATA_NONE if no error happen during the destruction or the error code corresponding to the encoutered error.
+ * @ingroup Evas_Cache
+ */
+EAPI Evas_Data_Error
+evas_cache_unreference	(Evas_Cache* cache, const char* key)
+{
+   Evas_Cache_Object*	obj = NULL;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return EVAS_DATA_NULL;
+
+   obj = _evas_cache_lookup (cache, key);
+   if (!obj)
+     {
+	cache->error = EVAS_DATA_NOT_FOUND;
+	return EVAS_DATA_NOT_FOUND;
+     }
+
+   obj->reference--;
+
+   return EVAS_DATA_NONE;
+}
+
+/**
+ * This function lookup in the cache if an object with the matching key exist. If found it will return a pointer to this object.
+ *
+ * @param cache	The cache in which we do our lookup.
+ * @param key	The key that could match an object.
+ * @return	A pointer to the object we found, or NULL if none match.
+ * @ingroup Evas_Cache
+ */
+EAPI void*
+evas_cache_find		(Evas_Cache* cache, const char* key)
+{
+   Evas_Cache_Object*	obj = NULL;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return NULL;
+
+   obj = _evas_cache_lookup (cache, key);
+   if (!obj)
+     {
+	cache->error = EVAS_DATA_NOT_FOUND;
+	return NULL;
+     }
+
+   return obj->object;
+}
+
+/**
+ * This function lookup in the cache if an object with the matching key exist. If found it will return the known size of the object.
+ *
+ * @param cache	The cache in which we do our lookup.
+ * @param key	The key that could match an object.
+ * @return	A pointer to the object we found, or NULL if none match.
+ * @ingroup Evas_Cache
+ */
+EAPI int
+evas_cache_find_size	(Evas_Cache* cache, const char* key)
+{
+   Evas_Cache_Object*	obj = NULL;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+
+   obj = _evas_cache_lookup (cache, key);
+   if (!obj)
+     {
+	cache->error = EVAS_DATA_NOT_FOUND;
+	return 0;
+     }
+
+   return obj->object_size;
+}
+
+/**
+ * This function return the global size of the cache.
+ *
+ * @param cache	The cache we want to learn the size of.
+ * @return	The size of the cache.
+ * @ingroup Evas_Cache
+ */
+EAPI int
+evas_cache_memsize	(Evas_Cache* cache)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+   return cache->current_size;
+}
+
+/**
+ * This function return the number of objects stored in the cache.
+ *
+ * @param cache	The cache we want to learn the number of objects from.
+ * @return	The number of object in this cache.
+ * @ingroup Evas_Cache
+ */
+EAPI int
+evas_cache_objects_count(Evas_Cache* cache)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+   return cache->current_objects_count;
+}
+
+/**
+ * This function force the flush of all object that have no external reference.
+ *
+ * @param cache	The cache we want to flush.
+ * @return	The number of object removed from the cache.
+ */
+EAPI int
+evas_cache_force_flush	(Evas_Cache* cache)
+{
+   int			before = 0;
+   int			i = 0;
+
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+
+   before = cache->current_objects_count;
+
+   while (i < cache->current_objects_count)
+     {
+	if (cache->objects[i].reference > 0)
+	  ++i;
+	else
+	  _evas_cache_remove_object (cache, i);
+     }
+
+   return before - cache->current_objects_count;
+}
+
+
+EAPI Evas_Data_Error
+evas_cache_set_maximum_size(Evas_Cache* cache, int max_size)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return EVAS_DATA_NULL;
+
+   cache->max_size = max_size;
+   return _evas_cache_match_size (cache, 0);
+}
+
+EAPI int
+evas_cache_get_maximum_size(Evas_Cache* cache)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+
+   return cache->max_size;
+}
+
+EAPI Evas_Data_Error
+evas_cache_set_maximum_objects	(Evas_Cache* cache, int max_objects_count)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return EVAS_DATA_NULL;
+
+   cache->max_objects_count = max_objects_count;
+   return _evas_cache_match_count (cache);
+}
+
+EAPI int
+evas_cache_get_maximum_objects	(Evas_Cache* cache)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return 0;
+
+   return cache->max_objects_count;
+}
+
+EAPI Evas_Data_Error
+evas_cache_get_last_error	(Evas_Cache* cache)
+{
+   if (!cache || cache->magic != EVAS_CACHE_MAGIC)
+     return EVAS_DATA_NULL;
+
+   return cache->error;
+}
+
+/** Private function */
+
+static int
+_evas_cache_lookup_int		(Evas_Cache* cache, const char* key)
+{
+   int				i = evas_hash_find (cache->cache_content, key) - 1;
+
+   if (i < 0)
+     return -1;
+
+   return i;
+}
+
+static Evas_Cache_Object*
+_evas_cache_lookup		(Evas_Cache* cache, const char* key)
+{
+   Evas_Cache_Object*		obj = NULL;
+   int				i = _evas_cache_lookup_int (cache, key);
+
+   if (i == - 1)
+     return NULL;
+
+   obj = cache->objects + i;
+   return obj;
+}
+
+static void
+_evas_cache_remove_object	(Evas_Cache* cache, int position)
+{
+   Evas_Cache_Object*		objects = cache->objects;
+   const char*			key = objects[position].key;
+   int				current_objects_count = 0;
+
+   if (cache->evict)
+     cache->evict (cache, key, objects[position].object, objects[position].reference);
+
+   current_objects_count = --(cache->current_objects_count);
+
+   cache->current_size -= objects[position].object_size;
+   cache->cache_content = evas_hash_del (cache->cache_content, key, NULL);
+
+   evas_stringshare_del (key);
+
+   memmove (objects + position, objects + position + 1, sizeof (struct _Evas_Cache_Object) * (current_objects_count - position));
+   memset (objects + current_objects_count, 0, sizeof (struct _Evas_Cache_Object));
+
+   if (cache->current_objects_limit - 8 > current_objects_count)
+     {
+	cache->current_objects_limit -= 8;
+	cache->objects = realloc (cache->objects, sizeof (struct _Evas_Cache_Object) * cache->current_objects_limit);
+     }
+}
+
+static int
+_evas_cache_less_used (Evas_Cache* cache)
+{
+   Evas_Cache_Object*	objects = cache->objects;
+   int			count = cache->current_objects_count;
+   int			requested_time = MAXINT;
+   int			i = 0;
+   int			to_be_killed = -1;
+
+   for (i = 0; i < count; ++objects, ++i)
+     if (objects->reference == 0 && requested_time > objects->requested_time)
+       {
+	  to_be_killed = i;
+	  requested_time = objects->requested_time;
+       }
+
+   return to_be_killed;
+}
+
+static Evas_Data_Error
+_evas_cache_match_size (Evas_Cache* cache, int adding_size)
+{
+   if (cache->max_size != 0 && cache->max_size < cache->current_size + adding_size)
+     {
+	/* This cache care a little about memory consuption, so comply with it */
+	while (cache->current_size + adding_size > cache->max_size)
+	  {
+	     int	i = _evas_cache_less_used (cache);
+
+	     if (i == -1)
+	       {
+		  cache->error = EVAS_DATA_FULL;
+		  return EVAS_DATA_FULL;
+	       }
+
+	     _evas_cache_remove_object (cache, i);
+	  }
+     }
+
+   return EVAS_DATA_NONE;
+}
+
+static Evas_Data_Error
+_evas_cache_match_count (Evas_Cache* cache)
+{
+   if (cache->max_objects_count != 0 && cache->max_objects_count < cache->current_objects_count + 1)
+     /* We reach the maximum number of stored object limit */
+     {
+	int	i = _evas_cache_less_used (cache);
+
+	if (i == -1)
+	  {
+	     cache->error = EVAS_DATA_FULL;
+	     return EVAS_DATA_FULL;
+	  }
+	_evas_cache_remove_object (cache, i);
+     }
+
+   return EVAS_DATA_NONE;
+}
+
+static int
+_evas_cache_empty_necessity (Evas_Cache* cache, int object_size, int force)
+{
+   if (!force && object_size > cache->max_size)
+     return -1;
+
+   if (!force && _evas_cache_match_size (cache, object_size) != EVAS_DATA_NONE)
+     return -1;
+
+   if (!force && _evas_cache_match_count (cache) != EVAS_DATA_NONE)
+     return -1;
+
+   if (cache->current_objects_limit < cache->current_objects_count + 1)
+     {
+	/* We need to expand the cache, step by step */
+	cache->current_objects_limit += 8;
+	cache->objects = realloc (cache->objects, sizeof (struct _Evas_Cache_Object) * cache->current_objects_limit);
+     }
+
+   return cache->current_objects_count;
+}
diff -Nru -x CVS e17-main/libs/evas/src/lib/data/Makefile.am e17-dev/libs/evas/src/lib/data/Makefile.am
--- e17-main/libs/evas/src/lib/data/Makefile.am	2005-11-28 16:18:00.000000000 +0100
+++ e17-dev/libs/evas/src/lib/data/Makefile.am	2006-07-27 10:47:46.000000000 +0200
@@ -15,6 +15,7 @@
 evas_hash.c \
 evas_list.c \
 evas_object_list.c \
-evas_stringshare.c
+evas_stringshare.c \
+evas_cache.c
 
 libevas_data_la_DEPENDENCIES = $(top_builddir)/config.h
diff -Nru -x CVS e17-main/libs/evas/config.h.in e17-dev/libs/evas/config.h.in
--- e17-main/libs/evas/config.h.in	2006-08-10 15:05:03.000000000 +0200
+++ e17-dev/libs/evas/config.h.in	2006-08-10 11:58:02.000000000 +0200
@@ -99,6 +99,9 @@
 /* OpenGL X11 Rendering Backend */
 #undef BUILD_ENGINE_GL_X11
 
+/* SDL Rendering Backend */
+#undef BUILD_ENGINE_SDL
+
 /* Qtopia Rendering Backend */
 #undef BUILD_ENGINE_SOFTWARE_QTOPIA
 
diff -Nru -x CVS e17-main/libs/evas/configure.in e17-dev/libs/evas/configure.in
--- e17-main/libs/evas/configure.in	2006-08-04 23:52:45.000000000 +0200
+++ e17-dev/libs/evas/configure.in	2006-08-09 20:54:07.000000000 +0200
@@ -63,6 +63,8 @@
 qt_cflags=""
 qt_libs=""				 
 qt_moc="moc"
+sdl_cflags=""
+sdl_libs=""
 
 #####################################################################
 
@@ -258,6 +260,58 @@
 AM_CONDITIONAL(BUILD_ENGINE_DIRECTFB, test "x$have_evas_directfb" = "xyes")
 
 #######################################
+## SDL
+AC_ARG_WITH(sdl-config, [  --with-sdl-config=SDL_CONFIG     use sdl-config specified],
+[ SDL_CONFIG=$withval;
+  echo "using "$SDL_CONFIG" for sdl-config"; ],
+[ if test -z "$SDL_CONFIG"; then
+    AC_PATH_PROG(SDL_CONFIG, "sdl-config", "", $PATH)
+  fi
+])
+if test -z "$SDL_CONFIG" ; then SDL_CONFIG="sdl-config"; fi
+
+#######################################
+## Check if we should build the sdl engine
+have_evas_sdl="no";
+ENGINE_SDL_PRG="";
+## Automatic check...
+AC_CHECK_HEADER(SDL/SDL.h,
+	[ have_evas_sdl="yes" ],
+	[ have_evas_sdl="no" ]
+)
+
+# Manual override
+AC_MSG_CHECKING(whether SDL backend is to be built)
+AC_ARG_ENABLE(sdl, AC_HELP_STRING([--enable-sdl],[enable the SDL rendering backend]), [
+           if test x"$enableval" = x"yes" ; then
+	     AC_MSG_RESULT(yes)
+	     have_evas_sdl="yes"
+	   else
+	     AC_MSG_RESULT(no)
+	     have_evas_sdl="no"
+	   fi
+        ], [
+           AC_MSG_RESULT($have_evas_sdl)
+	]
+)
+if test "x$have_evas_sdl" = "xyes"; then
+  if test "x$SDL_CONFIG" = "xno" ; then
+    have_evas_sdl= "no"
+    AM_CONDITIONAL(BUILD_ENGINE_SDL, false)
+    AC_MSG_RESULT(disabling sdl engine)
+  else
+    ENGINE_SDL_PRG="evas_sdl_test"
+    sdl_cflags=`$SDL_CONFIG --cflags`
+    sdl_libs=`$SDL_CONFIG --libs`
+    AM_CONDITIONAL(BUILD_ENGINE_SDL, true)
+    AC_DEFINE(BUILD_ENGINE_SDL, 1, [SDL Rendering Backend])
+  fi
+else
+  AM_CONDITIONAL(BUILD_ENGINE_SDL, false)
+  have_evas_sdl="no"
+fi
+
+#######################################
 ## Check if we should build the fb engine
 have_evas_fb="no";
 ENGINE_FB_PRG="";
@@ -1690,6 +1744,9 @@
 AC_SUBST(x_cflags)
 AC_SUBST(x_libs)
 
+AC_SUBST(sdl_cflags)
+AC_SUBST(sdl_libs)
+
 AC_SUBST(xcb_cflags)
 AC_SUBST(xcb_libs)
 AC_SUBST(xcbrender_cflags)
@@ -1731,6 +1788,7 @@
 AC_SUBST(ENGINE_SOFTWARE_X11_PRG)
 AC_SUBST(ENGINE_SOFTWARE_XCB_PRG)
 AC_SUBST(ENGINE_DIRECTFB_PRG)
+AC_SUBST(ENGINE_SDL_PRG)
 AC_SUBST(ENGINE_FB_PRG)
 AC_SUBST(ENGINE_BUFFER_PRG)
 AC_SUBST(ENGINE_SOFTWARE_QTOPIA_PRG)
@@ -1780,6 +1838,7 @@
 src/modules/engines/cairo_x11/Makefile
 src/modules/engines/xrender_x11/Makefile
 src/modules/engines/xrender_xcb/Makefile
+src/modules/engines/sdl/Makefile
 src/modules/loaders/Makefile
 src/modules/loaders/edb/Makefile
 src/modules/loaders/eet/Makefile
@@ -1823,6 +1882,7 @@
 echo "  Software Qtopia.........: $have_evas_qtopia"
 echo "  Software Memory Buffer..: $have_evas_buffer"
 echo "  DirectFB................: $have_evas_directfb"
+echo "  SDL.....................: $have_evas_sdl"
 echo "  OpenGL X11..............: $have_evas_gl_x11"
 echo "  Cairo X11...............: $have_evas_cairo_x11"
 echo "  XRender X11.............: $have_evas_xrender_x11"
diff -Nru -x CVS e17-main/libs/evas/README.in e17-dev/libs/evas/README.in
--- e17-main/libs/evas/README.in	2005-08-25 06:37:24.000000000 +0200
+++ e17-dev/libs/evas/README.in	2006-07-27 09:58:55.000000000 +0200
@@ -14,6 +14,7 @@
   X11R6
   XCB
   DirectFB
+  SDL
   OpenGL (underway at the moment)
   Linux
   Qtopia
@@ -127,6 +128,12 @@
 directfb that offer acceleration (otherwise the fb driver will likely be
 faster).
 
+--enable-sdl
+
+this is the sdl engine that uses sdl library (http://www.libsdl.org). This
+library should work on many operating system.
+
+
 CPU:
 --enable-cpu-c
 
diff -Nru -x CVS e17-main/libs/evas/src/bin/evas_sdl_main.c e17-dev/libs/evas/src/bin/evas_sdl_main.c
--- e17-main/libs/evas/src/bin/evas_sdl_main.c	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/bin/evas_sdl_main.c	2006-08-01 16:34:31.000000000 +0200
@@ -0,0 +1,39 @@
+#include "evas_test_main.h"
+
+#include "Evas.h"
+#include "Evas_Engine_SDL.h"
+
+#include <stdio.h>
+#include <string.h>
+
+int
+main(int argc, char **argv)
+{
+   int                 rot = 0;
+
+   evas_init();
+   evas = evas_new();
+   evas_output_method_set(evas, evas_render_method_lookup("sdl"));
+   evas_output_size_set(evas, win_w, win_h);
+   evas_output_viewport_set(evas, 0, 0, win_w, win_h);
+   {
+      Evas_Engine_Info_SDL *einfo;
+
+      einfo = (Evas_Engine_Info_SDL *) evas_engine_info_get(evas);
+
+      /* the following is specific to the engine */
+      einfo->info.fullscreen = 0;
+      einfo->info.noframe = 0;
+
+      evas_engine_info_set(evas, (Evas_Engine_Info *) einfo);
+   }
+   setup();
+   orig_start_time = start_time = get_time();
+   for (;;)
+     {
+	loop();
+	evas_render(evas);
+     }
+   evas_shutdown();
+   return 0;
+}
diff -Nru -x CVS e17-main/libs/evas/src/bin/Makefile.am e17-dev/libs/evas/src/bin/Makefile.am
--- e17-main/libs/evas/src/bin/Makefile.am	2006-07-13 21:48:09.000000000 +0200
+++ e17-dev/libs/evas/src/bin/Makefile.am	2006-08-07 18:53:00.000000000 +0200
@@ -3,6 +3,7 @@
 INCLUDES = \
 -I. -I$(top_srcdir)/src/modules/engines -I$(top_srcdir)/src/lib -I$(top_srcdir) \
 @DIRECTFB_CFLAGS@ @qt_cflags@ @gl_cflags@ \
+-I$(top_srcdir)/src/modules/engines/sdl \
 -I$(top_srcdir)/src/modules/engines/buffer \
 -I$(top_srcdir)/src/modules/engines/cairo_x11 \
 -I$(top_srcdir)/src/modules/engines/directfb \
@@ -28,7 +29,8 @@
 @ENGINE_GL_X11_PRG@ \
 @ENGINE_CAIRO_X11_PRG@ \
 @ENGINE_XRENDER_X11_PRG@ \
-@ENGINE_XRENDER_XCB_PRG@
+@ENGINE_XRENDER_XCB_PRG@ \
+@ENGINE_SDL_PRG@
 
 EXTRA_PROGRAMS = \
 evas_software_x11_test \
@@ -40,6 +42,7 @@
 evas_directfb_test \
 evas_directfb_window \
 evas_fb_test \
+evas_sdl_test \
 evas_buffer_test \
 evas_software_qtopia_test \
 evas_gl_x11_test \
@@ -94,4 +97,9 @@
 evas_fb_test_CFLAGS = $(CFLAGS)
 evas_fb_test_DEPENDENCIES = $(top_builddir)/src/lib/libevas.la
 
+evas_sdl_test_SOURCES = evas_test_main.h evas_test_main.c evas_sdl_main.c
+evas_sdl_test_LDADD = $(top_builddir)/src/lib/libevas.la -lm @sdl_libs@ @FREETYPE_LIBS@
+evas_sdl_test_CFLAGS = $(CFLAGS) @sdl_cflags@ @FREETYPE_CFLAGS@
+evas_sdl_test_DEPENDENCIES = $(top_builddir)/src/lib/libevas.la
+
 evas_buffer_test_SOURCES = evas_test_main.h evas_test_main.c evas_buffer_main.c
diff -Nru -x CVS e17-main/libs/evas/src/lib/Evas.h e17-dev/libs/evas/src/lib/Evas.h
--- e17-main/libs/evas/src/lib/Evas.h	2006-08-10 14:57:42.000000000 +0200
+++ e17-dev/libs/evas/src/lib/Evas.h	2006-08-10 11:40:24.000000000 +0200
@@ -307,6 +307,46 @@
    unsigned int   timestamp;
 };
 
+typedef struct _Evas_Cache		Evas_Cache;
+typedef struct _Evas_Cache_Object	Evas_Cache_Object;
+
+typedef enum _Evas_Data_Error
+{
+   EVAS_DATA_NONE = 0,
+   EVAS_DATA_NOT_FOUND,
+   EVAS_DATA_FULL,
+   EVAS_DATA_NULL,
+   EVAS_DATA_CONFLICT
+} Evas_Data_Error;
+
+struct _Evas_Cache_Object /** A cache object entry */
+{
+   const char*	key; /**< The key referencing this object */
+   void*	object;
+   int		object_size;
+   int		requested_time;
+   int		reference;
+};
+
+struct _Evas_Cache /** A cache */
+{
+   int			magic;
+
+   Evas_Hash*		cache_content; /**< The hash table for quick search */
+   Evas_Cache_Object*	objects; /**< Preallocated cache objects */
+   int			current_objects_limit;
+
+   int			max_objects_count;
+   int			max_size;
+
+   int			current_size;
+   int			current_objects_count;
+
+   Evas_Data_Error	error;
+
+   void			(*evict)(Evas_Cache* cache, const char* key, void* object, int reference);
+};
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -340,19 +380,34 @@
     *
     * do we really need this? hmmm - let me think... there may be a better way
     */
-   EAPI Evas_Hash        *evas_hash_add                     (Evas_Hash *hash, const char *key, const void *data);
-   EAPI Evas_Hash        *evas_hash_direct_add              (Evas_Hash *hash, const char *key, const void *data);
-   EAPI Evas_Hash        *evas_hash_del                     (Evas_Hash *hash, const char *key, const void *data);
+   EAPI Evas_Hash        *evas_hash_add                     (Evas_Hash *hash, const char *key, const void*data);
+   EAPI Evas_Hash        *evas_hash_direct_add              (Evas_Hash *hash, const char *key, const void*data);
+   EAPI Evas_Hash        *evas_hash_del                     (Evas_Hash *hash, const char *key, const void*data);
    EAPI void             *evas_hash_find                    (Evas_Hash *hash, const char *key);
-   EAPI void             *evas_hash_modify                  (Evas_Hash *hash, const char *key, const void *data);
+   EAPI void             *evas_hash_modify                  (Evas_Hash *hash, const char *key, const void*data);
    EAPI int               evas_hash_size                    (Evas_Hash *hash);
    EAPI void              evas_hash_free                    (Evas_Hash *hash);
    EAPI void              evas_hash_foreach                 (Evas_Hash *hash, Evas_Bool (*func) (Evas_Hash *hash, const char *key, void *data, void *fdata), const void *fdata);
    EAPI int               evas_hash_alloc_error             (void);
-   
+
    EAPI const char       *evas_stringshare_add              (const char *str);
    EAPI void              evas_stringshare_del              (const char *str);
-       
+
+   EAPI Evas_Cache	 *evas_cache_init		    (void (*evict)(Evas_Cache* cache, const char* key, void* object, int reference), int max_objects_count, int max_size);
+   EAPI Evas_Data_Error	  evas_cache_shutdown		    (Evas_Cache* cache);
+   EAPI void*		  evas_cache_reference		    (Evas_Cache* cache, const char* key);
+   EAPI void*		  evas_cache_update		    (Evas_Cache* cache, const char* key, void* object, int object_size, int force);
+   EAPI Evas_Data_Error   evas_cache_unreference	    (Evas_Cache* cache, const char* key);
+   EAPI void*		  evas_cache_find		    (Evas_Cache* cache, const char* key);
+   EAPI int		  evas_cache_find_size		    (Evas_Cache* cache, const char* key);
+   EAPI int		  evas_cache_memsize		    (Evas_Cache* cache);
+   EAPI int		  evas_cache_objects_count	    (Evas_Cache* cache);
+   EAPI int		  evas_cache_force_flush	    (Evas_Cache* cache);
+   EAPI Evas_Data_Error	  evas_cache_set_maximum_size	    (Evas_Cache* cache, int max_size);
+   EAPI int		  evas_cache_get_maximum_size	    (Evas_Cache* cache);
+   EAPI Evas_Data_Error	  evas_cache_set_maximum_objects    (Evas_Cache* cache, int max_objects_count);
+   EAPI int		  evas_cache_get_maximum_objects    (Evas_Cache* cache);
+   EAPI Evas_Data_Error	  evas_cache_get_last_error	    (Evas_Cache* cache);
 
    EAPI int               evas_alloc_error                  (void);
 
diff -Nru -x CVS e17-main/libs/evas/src/modules/engines/Makefile.am e17-dev/libs/evas/src/modules/engines/Makefile.am
--- e17-main/libs/evas/src/modules/engines/Makefile.am	2006-04-25 06:00:20.000000000 +0200
+++ e17-dev/libs/evas/src/modules/engines/Makefile.am	2006-07-26 23:41:52.000000000 +0200
@@ -14,4 +14,5 @@
 software_x11 \
 software_xcb \
 xrender_x11 \
-xrender_xcb
+xrender_xcb \
+sdl
diff -Nru -x CVS e17-main/libs/evas/src/modules/engines/sdl/evas_engine_sdl.c e17-dev/libs/evas/src/modules/engines/sdl/evas_engine_sdl.c
--- e17-main/libs/evas/src/modules/engines/sdl/evas_engine_sdl.c	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/modules/engines/sdl/evas_engine_sdl.c	2006-08-10 15:09:51.000000000 +0200
@@ -0,0 +1,975 @@
+#include "SDL/SDL.h"
+#include "evas_engine_sdl.h"
+#include "evas_common.h"
+#include "evas_private.h"
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+extern Evas_List*	evas_modules;
+
+static Evas_Func	func = {};
+static Evas_Func	pfunc = {};
+static Evas_Cache*	cache = NULL;
+
+static void		_sdl_evicted_image	(Evas_Cache* cache, const char* key, void* object, int reference);
+static void*		_sdl_output_setup	(int w, int h, int fullscreen, int noframe);
+static RGBA_Image*	_sdl_image_new_from_sdl	(SDL_Surface* sdl, const char* filename, const char* key);
+static RGBA_Image*	_sdl_image_new_from_file(const char* filename, const char* key);
+static void		_sdl_image_free		(RGBA_Image* im);
+static void		_sdl_debug_rgba_image	(RGBA_Image* im);
+static void		_sdl_stretch_blit	(RGBA_Image* from, RGBA_Image* to, int w, int h);
+
+/* Stupid macro often used */
+#define	CHECK_CACHE(COUNT, SIZE) \
+	if (!cache) cache = evas_cache_init (&_sdl_evicted_image, COUNT, SIZE);
+#define	_SDL_BUILD_HASH_KEY(COMPUTE, FILENAME, KEY, RET) \
+	{ \
+	   int	lfilename = (FILENAME) ? strlen (FILENAME) : 0; \
+	   int	lkey = (KEY) ? strlen (KEY) : 4; \
+	   int	lsum = lfilename + 3 + lkey + 4; \
+\
+	   COMPUTE = alloca (lsum); \
+	   if (!COMPUTE) \
+	     return RET; \
+\
+	   snprintf (COMPUTE, lsum, "%s/:/%s/:/", FILENAME, KEY ? KEY : "null"); \
+	}
+#define _SDL_UPDATE_PIXELS(IM) \
+	IM->image->data = ((SDL_Surface*) IM->extended_info)->pixels;
+#define _SDL_CACHE_UPDATE(REAL_KEY, IM) \
+	{ \
+		RGBA_Image*	rim = NULL; \
+		rim = evas_cache_update(cache, \
+					REAL_KEY, \
+					IM, evas_common_image_ram_usage (im), \
+					1); \
+		if (!rim) \
+			_sdl_image_free(IM); \
+		*error = evas_cache_get_last_error(cache); \
+	}
+
+/* SDL engine info function */
+static void*
+evas_engine_sdl_info		(Evas* e)
+{
+   Evas_Engine_Info_SDL*	info = calloc(1, sizeof (Evas_Engine_Info_SDL));
+
+   if (!info)
+      return NULL;
+
+   info->magic.magic = rand();
+
+   return info;
+}
+
+static void
+evas_engine_sdl_info_free	(Evas* e, void* info)
+{
+   Evas_Engine_Info_SDL*	in = (Evas_Engine_Info_SDL*) info;
+
+   free(in);
+   in = NULL;
+}
+
+/* SDL engine output manipulation function */
+static void
+evas_engine_sdl_setup		(Evas* e, void* in)
+{
+   Evas_Engine_Info_SDL*	info = (Evas_Engine_Info_SDL*) in;
+
+   /* if we arent set to sdl, why the hell do we get called?! */
+   if (evas_output_method_get(e) != evas_render_method_lookup("sdl"))
+      return ;
+
+   if (SDL_Init(SDL_INIT_VIDEO) < 0)
+     {
+	fprintf(stderr, "SDL_Init failed with %s\n", SDL_GetError());
+        exit(-1);
+     }
+   atexit(SDL_Quit);
+
+   /* lets just set up */
+   e->engine.data.output = _sdl_output_setup(e->output.w, e->output.h,
+					     info->info.fullscreen,
+					     info->info.noframe);
+
+   if (!e->engine.data.output)
+      return;
+
+   e->engine.func = &func;
+   e->engine.data.context = e->engine.func->context_new(e->engine.data.output);
+   info->info.surface = ((Render_Engine*) e->engine.data.output)->surface;
+}
+
+static void
+evas_engine_sdl_output_free	(void *data)
+{
+   Render_Engine*		re = (Render_Engine*) data;
+
+   evas_common_tilebuf_free(re->tb);
+   if (re->rects)
+      evas_common_tilebuf_free_render_rects(re->rects);
+   _sdl_image_free(re->rgba_image);
+
+   if (re->update_rects)
+     free(re->update_rects);
+   memset(re, sizeof (Render_Engine), 0);
+   free(re);
+
+   evas_common_font_shutdown();
+   evas_common_image_shutdown();
+}
+
+static void
+evas_engine_sdl_output_resize	(void *data, int w, int h)
+{
+   Render_Engine*		re = (Render_Engine*) data;
+   RGBA_Image*			im = NULL;
+   SDL_Surface*			tmp = NULL;
+
+   if (w == re->tb->outbuf_w && h == re->tb->outbuf_h)
+     return;
+
+   /* Make a copy of the scren */
+   tmp = SDL_DisplayFormatAlpha(re->surface);
+   if (!tmp)
+     return ;
+   im = _sdl_image_new_from_sdl(tmp, NULL, "SCREEN-OLD");
+
+   /* Destroy the screen */
+   _sdl_image_free (re->rgba_image);
+
+   /* Rebuil tilebuf */
+   evas_common_tilebuf_free(re->tb);
+   re->tb = evas_common_tilebuf_new(w, h);
+   if (re->tb)
+      evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+
+   /* Build the new screen */
+   re->surface = SDL_SetVideoMode(w, h, 32,
+				  SDL_SWSURFACE
+				  | (re->fullscreen ? SDL_FULLSCREEN : 0)
+				  | (re->noframe ? SDL_NOFRAME : 0));
+
+   if (!re->surface)
+     {
+	fprintf(stderr, "Unable to change the resolution to : %ix%i\n", w, h);
+	exit(-1);
+     }
+   re->rgba_image = _sdl_image_new_from_sdl(re->surface, NULL, "SCREEN");
+   if (!re->rgba_image)
+     {
+	fprintf(stderr, "RGBA_Image allocation from SDL failed\n");
+	exit(-1);
+     }
+
+   /* Blit the old content to the new screen */
+   _sdl_stretch_blit(im, re->rgba_image, w, h);
+
+   /* Destroy the copy */
+   _sdl_image_free(im);
+}
+
+static void
+evas_engine_sdl_output_tile_size_set	(void *data, int w, int h)
+{
+   Render_Engine*			re = (Render_Engine*) data;
+
+   evas_common_tilebuf_set_tile_size(re->tb, w, h);
+}
+
+static void
+evas_engine_sdl_output_redraws_rect_add	(void *data, int x, int y, int w, int h)
+{
+   Render_Engine*			re = (Render_Engine*) data;
+
+   evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
+}
+
+static void
+evas_engine_sdl_output_redraws_rect_del	(void *data, int x, int y, int w, int h)
+{
+   Render_Engine*			re = (Render_Engine*) data;
+
+   evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
+}
+
+static void
+evas_engine_sdl_output_redraws_clear	(void *data)
+{
+   Render_Engine*			re = (Render_Engine*) data;
+
+   evas_common_tilebuf_clear(re->tb);
+}
+
+static void*
+evas_engine_sdl_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 = (Render_Engine*) data;
+   Tilebuf_Rect*				tb_rect = NULL;
+
+   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;
+     }
+
+   /* Return the "fake" surface so it is passed to the drawing routines. */
+   return re->rgba_image;
+}
+
+static void
+evas_engine_sdl_output_redraws_next_update_push	(void *data, void *surface,
+						 int x, int y, int w, int h)
+{
+   Render_Engine				*re = (Render_Engine *) data;
+
+   if (re->update_rects_count + 1 > re->update_rects_limit)
+     {
+	re->update_rects_limit += 8;
+	re->update_rects = realloc(re->update_rects, sizeof (SDL_Rect) * re->update_rects_limit);
+     }
+
+   re->update_rects[re->update_rects_count].x = x;
+   re->update_rects[re->update_rects_count].y = y;
+   re->update_rects[re->update_rects_count].w = w;
+   re->update_rects[re->update_rects_count].h = h;
+
+   ++re->update_rects_count;
+
+   evas_common_cpu_end_opt();
+}
+
+static void
+evas_engine_sdl_output_flush			(void *data)
+{
+   Render_Engine				*re = (Render_Engine *) data;
+
+   SDL_UpdateRects(re->surface, re->update_rects_count, re->update_rects);
+
+   re->update_rects_count = 0;
+}
+
+/*
+ * Image objects
+ */
+
+static void*
+evas_engine_sdl_image_load(void *data, const char *file, const char *key, int *error)
+{
+   char*		real_key = NULL;
+   Render_Engine*	re = (Render_Engine*) data;;
+   RGBA_Image*		im = NULL;
+   SDL_Surface*		sdl = NULL;
+   SDL_Surface*		tmp = NULL;
+
+   *error = 0;
+
+   if (!file)
+     return NULL;
+
+   CHECK_CACHE(0, 0);
+
+   _SDL_BUILD_HASH_KEY(real_key, file, key, NULL);
+   im = evas_cache_reference(cache, real_key);
+   if (im)
+     {
+	if (!(im->flags & RGBA_IMAGE_IS_DIRTY))
+	  return im;
+	else
+	  evas_cache_unreference(cache, real_key);
+     }
+
+   /* Image is not in cache -> create it */
+
+   /* First try to load the image directly with SDL */
+   tmp = SDL_LoadBMP(file);
+   if (tmp)
+     {
+	if (tmp->pixels != NULL)
+	  {
+	     if ((sdl = SDL_DisplayFormatAlpha(tmp)))
+	       {
+		  SDL_FreeSurface(tmp);
+		  im = _sdl_image_new_from_sdl(sdl, file, key);
+
+		  /* The update could failed if the real_key is already present
+		     but dirty in the cache */
+		  _SDL_CACHE_UPDATE(real_key, im);
+		  return evas_cache_reference(cache, real_key);
+	       }
+	  }
+	SDL_FreeSurface(tmp);
+	tmp = NULL;
+     }
+
+   /* Failed, so use fallback */
+   im = _sdl_image_new_from_file(file, key);
+   if (im)
+     {
+	evas_common_load_image_data_from_file(im);
+	/* Convert the loaded image to a SDL_Surface */
+	tmp = SDL_CreateRGBSurfaceFrom(im->image->data,
+				       im->image->w, im->image->h,
+				       32, im->image->w * 4,
+				       0xff0000, 0xff00, 0xff, 0xff000000);
+	if (tmp)
+	  {
+	     sdl = SDL_DisplayFormatAlpha(tmp);
+	     SDL_FreeSurface(tmp);
+	     if (sdl)
+	       {
+		  free(im->image->data);
+
+		  im->image->data = (void*) sdl->pixels;
+		  im->image->no_free = 1;
+		  im->extended_info = sdl;
+
+		  /* The update could failed if the real_key is already present
+		     but dirty in the cache */
+		  _SDL_CACHE_UPDATE(real_key, im);
+		  im = evas_cache_reference(cache, real_key);
+		  return im;
+	       }
+	  }
+	_sdl_image_free(im);
+     }
+   return NULL;
+}
+
+static void*
+evas_engine_sdl_image_new_from_copied_data(void *data,
+					   int w, int h,
+					   DATA32* image_data)
+{
+   Render_Engine	*re = (Render_Engine*) data;
+   RGBA_Image		*im = NULL;
+   SDL_Surface		*sdl = NULL;
+
+   CHECK_CACHE(0, 0);
+
+   sdl = SDL_CreateRGBSurfaceFrom(image_data,
+				  w, h,
+				  32, w * 4,
+				  0xff0000, 0xff00, 0xff, 0xff000000);
+
+   if (sdl)
+     {
+	RGBA_Image*	rim = NULL;
+	char*		real_key = NULL;
+
+	im = _sdl_image_new_from_sdl(sdl, NULL, NULL);
+	im->image->no_free = 0;
+	_SDL_BUILD_HASH_KEY(real_key, im->info.file, im->info.key, NULL);
+	evas_cache_update(cache, real_key, im, evas_common_image_ram_usage(im), 1);
+
+	return evas_cache_reference(cache, real_key);
+     }
+   return NULL;
+}
+
+static void*
+evas_engine_sdl_image_new_from_data(void *data, int w, int h, DATA32* image_data)
+{
+   return evas_engine_sdl_image_new_from_copied_data(data, w, h, image_data);
+}
+
+static void
+evas_engine_sdl_image_free(void *data, void *image)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   char*		key = NULL;
+   RGBA_Image*		im = (RGBA_Image*) image;
+
+   CHECK_CACHE(0, 0);
+   _SDL_BUILD_HASH_KEY(key, im->info.file, im->info.key, );
+
+   evas_cache_unreference(cache, key);
+}
+
+static void*
+evas_engine_sdl_image_size_set(void *data, void *image, int w, int h)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im_old = (RGBA_Image*) image;
+   RGBA_Image*		im = NULL;
+   char*		key = NULL;
+   SDL_Surface*		sdl = NULL;
+
+   CHECK_CACHE(0, 0);
+   _SDL_BUILD_HASH_KEY(key, im_old->info.file, im_old->info.key, NULL);
+
+   sdl = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA,
+			      w, h, 32,
+			      0xff0000, 0xff00, 0xff, 0xff000000);
+   if (!sdl)
+     return im_old;
+
+   im = _sdl_image_new_from_sdl(sdl, im_old->info.file, im_old->info.key);
+   if (!im)
+     {
+	SDL_FreeSurface(sdl);
+	return im_old;
+     }
+
+   if (im_old)
+     {
+	evas_common_load_image_data_from_file(im_old);
+	if (im_old->image->data)
+	  _sdl_stretch_blit (im_old, im, w, h);
+
+	evas_cache_unreference(cache, key);
+	/* This update could failed if the real_key is still referenced by someone */
+	if (!evas_cache_update(cache,
+			       key, im, evas_common_image_ram_usage (im),
+			       1))
+	  _sdl_image_free(im);
+     }
+   return evas_cache_reference(cache, key);
+}
+
+void*
+evas_engine_sdl_image_dirty_region(void *data,
+				   void *image,
+				   int x, int y, int w, int h)
+{
+   RGBA_Image*		im = (RGBA_Image*) image;
+
+   im->flags |= RGBA_IMAGE_IS_DIRTY;
+
+   return image;
+}
+
+void*
+evas_engine_sdl_image_data_get(void *data, void *image,
+			       int to_write, DATA32** image_data)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im = (RGBA_Image*) image;
+   DATA32*		buffer = NULL;
+   int			size = im->image->w * im->image->h * sizeof (DATA32);
+
+   buffer = malloc (size);
+   if (buffer)
+     {
+	if (im->extended_info && SDL_MUSTLOCK(((SDL_Surface*) im->extended_info)))
+	  {
+	     SDL_LockSurface(im->extended_info);
+	     _SDL_UPDATE_PIXELS(im);
+	  }
+
+	memcpy (buffer, im->image->data, size);
+
+	if (im->extended_info && SDL_MUSTLOCK(((SDL_Surface*) im->extended_info)))
+	  SDL_UnlockSurface(im->extended_info);
+     }
+   *image_data = buffer;
+
+   return im;
+}
+
+void*
+evas_engine_sdl_image_data_put(void *data, void *image, DATA32* image_data)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im = (RGBA_Image*) image;
+   SDL_Surface*		sdl = NULL;
+
+   CHECK_CACHE(0, 0);
+   if (image_data != im->image->data)
+     {
+	char*		str = NULL;
+	int		w = im->image->w;
+	int		h = im->image->h;
+
+	_SDL_BUILD_HASH_KEY(str, im->info.file, im->info.key, NULL);
+	evas_cache_unreference (cache, str);
+
+	sdl = SDL_CreateRGBSurfaceFrom (image_data,
+					w, h, 32, w * 4,
+					0xff0000, 0xff00, 0xff, 0xff000000);
+	if (sdl)
+	  {
+	     im = _sdl_image_new_from_sdl (sdl, im->info.file, im->info.key);
+	     if (im)
+	       {
+		  im->image->no_free = 0;
+		  /* This update could failed if the real_key is
+		     still referenced by someone */
+		  if (!evas_cache_update (cache,
+					  str, im, evas_common_image_ram_usage (im),
+					  1))
+		    _sdl_image_free (im);
+	       }
+	     else
+	       SDL_FreeSurface (sdl);
+	     return evas_cache_reference (cache, str);
+	  }
+	return NULL;
+     }
+
+   im->flags |= RGBA_IMAGE_IS_DIRTY;
+   return im;
+}
+
+void*
+evas_engine_sdl_image_alpha_set(void *data, void *image, int has_alpha)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im = (RGBA_Image*) image;
+
+   /* FIXME: update SDL_Surface flags */
+   if (has_alpha)
+      im->flags |= RGBA_IMAGE_HAS_ALPHA;
+   else
+      im->flags &= ~RGBA_IMAGE_HAS_ALPHA;
+   return im;
+}
+
+int
+evas_engine_sdl_image_alpha_get(void *data, void *image)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im = (RGBA_Image*) image;
+
+   if (im->flags & RGBA_IMAGE_HAS_ALPHA)
+     return 1;
+   return 0;
+}
+
+void*
+evas_engine_sdl_image_border_set(void *data, void *image, int l, int r, int t, int b)
+{
+   /* FIXME: need to know what evas expect from this call */
+   return image;
+}
+
+void
+evas_engine_sdl_image_border_get(void *data, void *image, int *l, int *r, int *t, int *b)
+{
+   /* FIXME: need to know what evas expect from this call */
+}
+
+void
+evas_engine_sdl_image_draw(void *data, void *context, void *surface, void *image,
+			   int src_region_x, int src_region_y, int src_region_w, int src_region_h,
+			   int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h,
+			   int smooth)
+{
+   Render_Engine*	re = (Render_Engine*) data;
+   RGBA_Image*		im = (RGBA_Image*) image;
+   RGBA_Draw_Context*	dc = (RGBA_Draw_Context*) context;
+
+   /* Fallback to software method */
+   if (SDL_MUSTLOCK(((SDL_Surface*) re->surface)))
+     {
+	SDL_LockSurface (re->surface);
+	_SDL_UPDATE_PIXELS(re->rgba_image);
+     }
+
+   if (im->extended_info && SDL_MUSTLOCK(((SDL_Surface*) im->extended_info)))
+     {
+	SDL_LockSurface (im->extended_info);
+	_SDL_UPDATE_PIXELS(im);
+     }
+
+   if (smooth)
+     evas_common_scale_rgba_in_to_out_clip_smooth (im, re->rgba_image, dc,
+						   src_region_x, src_region_y, src_region_w, src_region_h,
+						   dst_region_x, dst_region_y, dst_region_w, dst_region_h);
+   else
+     evas_common_scale_rgba_in_to_out_clip_sample (im, re->rgba_image, dc,
+						   src_region_x, src_region_y, src_region_w, src_region_h,
+						   dst_region_x, dst_region_y, dst_region_w, dst_region_h);
+   if (im->extended_info && SDL_MUSTLOCK(((SDL_Surface*) im->extended_info)))
+     SDL_UnlockSurface (im->extended_info);
+
+   if (SDL_MUSTLOCK(((SDL_Surface*) re->surface)))
+     SDL_UnlockSurface (re->surface);
+
+   evas_common_cpu_end_opt ();
+}
+
+void
+evas_engine_sdl_image_cache_flush(void *data)
+{
+   CHECK_CACHE(0, 0);
+   evas_cache_force_flush (cache);
+}
+
+void
+evas_engine_sdl_image_cache_set(void *data, int bytes)
+{
+   CHECK_CACHE(0, 0);
+   evas_cache_set_maximum_size (cache, bytes);
+}
+
+int
+evas_engine_sdl_image_cache_get(void *data)
+{
+   CHECK_CACHE(0, 0);
+   return evas_cache_get_maximum_size (cache);
+}
+
+char*
+evas_engine_sdl_image_comment_get(void *data, void *image, char *key)
+{
+   RGBA_Image         *im = (RGBA_Image*) image;
+
+   return im->info.comment;
+}
+
+char*
+evas_engine_sdl_image_format_get(void *data, void *image)
+{
+   /* FIXME: need to know what evas expect from this call */
+   return NULL;
+}
+
+
+int module_open(Evas_Module *em)
+{
+   if (!em) return 0;
+   /* get whatever engine module we inherit from */
+   if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
+   /* store it for later use */
+   func = pfunc;
+   /* now to override methods */
+#define ORD(f) EVAS_API_OVERRIDE(f, &func, evas_engine_sdl_)
+   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(image_load);
+   ORD(image_new_from_data);
+   ORD(image_new_from_copied_data);
+   ORD(image_free);
+   ORD(image_size_set);
+   ORD(image_dirty_region);
+   ORD(image_data_get);
+   ORD(image_data_put);
+   ORD(image_alpha_set);
+   ORD(image_alpha_get);
+   ORD(image_border_set);
+   ORD(image_border_get);
+   ORD(image_draw);
+   ORD(image_comment_get);
+   ORD(image_format_get);
+   ORD(image_cache_flush);
+   ORD(image_cache_set);
+   ORD(image_cache_get);
+   /* now advertise out own api */
+   em->functions = (void *)(&func);
+   return 1;
+}
+
+void module_close(void)
+{
+
+}
+
+Evas_Module_Api evas_modapi =
+{
+   EVAS_MODULE_API_VERSION,
+   EVAS_MODULE_TYPE_ENGINE,
+   "sdl",
+   "none"
+};
+
+/*
+ * Private routines. These are slightly modified versions of the ones in
+ * engines/sdl/evas_engine_sdl_image_objects.c
+ */
+
+struct ext_loader_s {
+   const char*	extention;
+   const char*	loader;
+};
+
+static struct ext_loader_s	loaders[] = {
+   { "png", "png" },
+   { "jpg", "jpeg" },
+   { "jpeg", "jpeg" },
+   { "jfif", "jpeg" },
+   { "eet", "eet" },
+   { "edj", "eet" },
+   { "eap", "eet" },
+   { "edb", "edb" }
+};
+
+static RGBA_Image*
+_sdl_image_loader (RGBA_Image*	im, const char* filename, const char* key)
+{
+   Evas_List*			l = NULL;
+   char*			dot = NULL;
+   const char*			loader = NULL;
+   int				i = 0;
+
+   if (!filename)
+     return im;
+
+   dot = strrchr (filename, '.');
+   if (dot)
+     {
+	for (i = 0, ++dot; i < (sizeof (loaders) / sizeof (struct ext_loader_s)); ++i)
+	  {
+	     if (!strcasecmp (dot, loaders[i].extention))
+	       {
+		  loader = loaders[i].loader;
+		  break;
+	       }
+	  }
+     }
+
+   if (loader)
+     {
+	Evas_Module*	em = NULL;
+
+	em = evas_module_find_type (EVAS_MODULE_TYPE_IMAGE_LOADER, loader);
+	if (em && evas_module_load (em))
+	  {
+	     Evas_Image_Load_Func*	evas_image_load_func = em->functions;
+
+	     if (evas_image_load_func->file_head (im, filename, key))
+	       {
+		  im->info.loader = (void*) evas_image_load_func;
+		  return im;
+	       }
+	  }
+     }
+
+   for (l = evas_modules; l; l = l->next)
+     {
+	Evas_Image_Load_Func*	evas_image_load_func = NULL;
+	Evas_Module*		em = NULL;
+
+	em = l->data;
+	if (em->type != EVAS_MODULE_TYPE_IMAGE_LOADER) continue;
+	if (!evas_module_load (em)) continue;
+	evas_image_load_func = em->functions;
+	if (evas_image_load_func->file_head (im, filename, key))
+	  {
+	     im->info.loader = (void*) evas_image_load_func;
+	     return im;
+	  }
+     }
+
+   _sdl_image_free (im);
+   return NULL;
+}
+
+static RGBA_Image*
+_sdl_image_new_from_file (const char* filename, const char* key)
+{
+   RGBA_Image		*im = NULL;
+   char*		final_key = key ? NULL : alloca (sizeof (char) * 10);
+
+   im = evas_common_image_new ();
+   if (!im)
+     return NULL;
+   im->image = evas_common_image_surface_new (im);
+   if (!im->image)
+     {
+	evas_common_image_free (im);
+	return NULL;
+     }
+
+   im = _sdl_image_loader (im, filename, key);
+   if (!im)
+     return NULL;
+
+   im->image->data = NULL;
+   im->image->no_free = 1;
+   im->extended_info = NULL;
+
+   im->info.file = (char*) evas_stringshare_add (filename ? filename : "unknown");
+   if (!key)
+     {
+	if (!filename)
+	  {
+	     struct timeval	tv;
+
+	     gettimeofday(&tv, NULL);
+	     snprintf (final_key, 10, "%i", (tv.tv_sec & 0xFFFFFFFF) ^ (tv.tv_usec & 0xFFFFFFFF));
+	  }
+	else
+	  final_key = "null";
+     }
+   else
+     final_key = (char*) key;
+
+   im->info.key = (char*) evas_stringshare_add (final_key);
+
+   return im;
+}
+
+static RGBA_Image*
+_sdl_image_new_from_sdl (SDL_Surface* sdl, const char* filename, const char* key)
+{
+   RGBA_Image*		im = _sdl_image_new_from_file (filename, key);
+
+   if (!im)
+     return NULL;
+
+   im->image->data = (void*) sdl->pixels;
+   im->image->no_free = 1;
+   im->extended_info = sdl;
+   im->image->w = sdl->w;
+   im->image->h = sdl->h;
+
+   if (sdl->flags & SDL_SRCALPHA)
+     im->flags |= RGBA_IMAGE_HAS_ALPHA;
+
+   return im;
+}
+
+static void
+_sdl_image_free (RGBA_Image* im)
+{
+   if (im->image && im->extended_info)
+     SDL_FreeSurface(im->extended_info);
+   evas_common_image_free (im);
+}
+
+static void
+_sdl_evicted_image (Evas_Cache* cache, const char* key, void* object, int reference)
+{
+   RGBA_Image* im = (RGBA_Image*) object;
+
+   _sdl_image_free (im);
+}
+
+static void*
+_sdl_output_setup		(int w, int h, int fullscreen, int noframe)
+{
+   Render_Engine		*re = calloc(1, sizeof(Render_Engine));
+
+   /* if we haven't initialized - init (automatic abort if already done) */
+   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();
+
+   re->tb = evas_common_tilebuf_new(w, h);
+   /* in preliminary tests 16x16 gave highest framerates */
+   evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+
+   re->surface = SDL_SetVideoMode(w, h, 32,
+				  SDL_SWSURFACE
+				  | (fullscreen ? SDL_FULLSCREEN : 0)
+				  | (noframe ? SDL_NOFRAME : 0));
+   if (!re->surface)
+     return NULL;
+
+   SDL_SetAlpha(re->surface, SDL_SRCALPHA | SDL_RLEACCEL, 0);
+
+   /* We create a "fake" RGBA_Image which points to the SDL surface. Each access
+    * to that surface is wrapped in Lock / Unlock calls whenever the data is
+    * manipulated directly. */
+   re->rgba_image = _sdl_image_new_from_sdl (re->surface, NULL, "SCREEN");
+
+   if (!re->rgba_image)
+     {
+	fprintf(stderr, "RGBA_Image allocation from SDL failed\n");
+        exit (-1);
+     }
+
+   re->fullscreen = fullscreen;
+   re->noframe = noframe;
+   return re;
+}
+
+static void
+_sdl_debug_rgba_image		(RGBA_Image* im)
+{
+   printf ("*** Image (%p) ***\n", im);
+   if (im)
+     {
+	printf ("* W: %i\n* H: %i\n", im->image->w, im->image->h);
+	printf ("* Pixels: %p\n* SDL Surface: %p\n", im->image->data, im->extended_info);
+	printf ("* Flags: %i\n", im->flags);
+	printf ("* Filename: %s\n* Key: %s\n", im->info.file, im->info.key);
+	printf ("* SDL_Surface: %p\n", im->extended_info);
+     }
+   printf ("*** ***\n");
+}
+
+static void
+_sdl_stretch_blit		(RGBA_Image* from,
+				 RGBA_Image* to,
+				 int w, int h)
+{
+   int				is_sdl_from = 0;
+   int				is_sdl_to = 0;
+
+   if (from->extended_info)
+     is_sdl_from = 1;
+   if (to->extended_info)
+     is_sdl_to = 1;
+
+   if (is_sdl_from)
+     {
+	if (SDL_MUSTLOCK(((SDL_Surface*) from->extended_info)))
+	  {
+	     SDL_LockSurface(from->extended_info);
+	     _SDL_UPDATE_PIXELS(from);
+	  }
+     }
+
+   if (is_sdl_to)
+     if (SDL_MUSTLOCK(((SDL_Surface*) to->extended_info)))
+       {
+	  SDL_LockSurface(to->extended_info);
+	  _SDL_UPDATE_PIXELS(to);
+       }
+
+   evas_common_blit_rectangle(from, to, 0, 0, w, h, 0, 0);
+
+   if (is_sdl_to && SDL_MUSTLOCK(((SDL_Surface*) to->extended_info)))
+     SDL_UnlockSurface(to->extended_info);
+
+   if (is_sdl_from && SDL_MUSTLOCK(((SDL_Surface*) from->extended_info)))
+     SDL_UnlockSurface(from->extended_info);
+
+   evas_common_cpu_end_opt();
+}
diff -Nru -x CVS e17-main/libs/evas/src/modules/engines/sdl/evas_engine_sdl.h e17-dev/libs/evas/src/modules/engines/sdl/evas_engine_sdl.h
--- e17-main/libs/evas/src/modules/engines/sdl/evas_engine_sdl.h	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/modules/engines/sdl/evas_engine_sdl.h	2006-08-09 00:02:44.000000000 +0200
@@ -0,0 +1,24 @@
+#ifndef EVAS_ENGINE_SDL_H
+#define EVAS_ENGINE_SDL_H
+#include "evas_common.h"
+#include "evas_private.h"
+#include "Evas_Engine_SDL.h"
+
+typedef struct _Render_Engine Render_Engine;
+
+struct _Render_Engine
+{
+   Tilebuf*		tb;
+   Tilebuf_Rect*	rects;
+   Evas_Object_List*	cur_rect;
+   SDL_Surface*		surface;
+   RGBA_Image*		rgba_image;
+   SDL_Rect*		update_rects;
+   int			update_rects_count;
+   int			update_rects_limit;
+   int			fullscreen:1;
+   int			noframe:1;
+   int			end:1;
+};
+
+#endif
diff -Nru -x CVS e17-main/libs/evas/src/modules/engines/sdl/Evas_Engine_SDL.h e17-dev/libs/evas/src/modules/engines/sdl/Evas_Engine_SDL.h
--- e17-main/libs/evas/src/modules/engines/sdl/Evas_Engine_SDL.h	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/modules/engines/sdl/Evas_Engine_SDL.h	2006-08-01 16:33:12.000000000 +0200
@@ -0,0 +1,22 @@
+#ifndef _EVAS_ENGINE_SDL_H
+#define _EVAS_ENGINE_SDL_H
+
+#include <SDL/SDL.h>
+
+typedef struct _Evas_Engine_Info_SDL Evas_Engine_Info_SDL;
+
+struct _Evas_Engine_Info_SDL
+{
+   /* 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 {
+      SDL_Surface		*surface;
+      int			fullscreen : 1;
+      int			noframe : 1;
+   } info;
+};
+#endif
+
+
diff -Nru -x CVS e17-main/libs/evas/src/modules/engines/sdl/Makefile.am e17-dev/libs/evas/src/modules/engines/sdl/Makefile.am
--- e17-main/libs/evas/src/modules/engines/sdl/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ e17-dev/libs/evas/src/modules/engines/sdl/Makefile.am	2006-08-01 14:45:19.000000000 +0200
@@ -0,0 +1,28 @@
+AUTOMAKE_OPTIONS     = 1.4 foreign
+
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES = -I. -I$(top_srcdir)/src/lib -I$(top_srcdir)/src/lib/include @FREETYPE_CFLAGS@ @DIRECTFB_CFLAGS@
+
+if BUILD_ENGINE_SDL
+
+pkgdir = $(libdir)/evas/modules/engines/sdl/$(MODULE_ARCH)
+
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES  = \
+evas_engine_sdl.c \
+evas_engine_sdl.h
+
+module_la_LIBADD = @DIRECTFB_LIBS@ $(top_builddir)/src/lib/libevas.la
+module_la_LDFLAGS = -module -avoid-version -L$(top_builddir)/src/lib -L$(top_builddir)/src/lib/.libs
+module_la_DEPENDENCIES = $(top_builddir)/config.h
+
+include_HEADERS = Evas_Engine_SDL.h
+
+endif
+
+EXTRA_DIST = \
+evas_engine_sdl.c \
+evas_engine_sdl.h \
+Evas_Engine_SDL.h