/*
   (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <config.h>

#include <limits.h>
#include <string.h>

#include <directfb.h>

#include <direct/debug.h>
#include <direct/memcpy.h>

#include <fusion/fusion.h>
#include <fusion/shmalloc.h>
#include <fusion/arena.h>
#include <fusion/property.h>

#include <core/core.h>
#include <core/coredefs.h>
#include <core/coretypes.h>

#include <core/core_parts.h>
#include <core/gfxcard.h>
#include <core/fonts.h>
#include <core/state.h>
#include <core/palette.h>
#include <core/surface.h>
#include <core/surface_buffer.h>
#include <core/surface_pool.h>
#include <core/system.h>

#include <gfx/generic/generic.h>
#include <gfx/clip.h>
#include <gfx/util.h>

#include <direct/hash.h>
#include <direct/mem.h>
#include <direct/messages.h>
#include <direct/modules.h>
#include <direct/utf8.h>
#include <direct/util.h>

#include <misc/conf.h>
#include <misc/util.h>


D_DEBUG_DOMAIN( Core_Graphics,    "Core/Graphics",    "DirectFB Graphics Core" );
D_DEBUG_DOMAIN( Core_GraphicsOps, "Core/GraphicsOps", "DirectFB Graphics Core Operations" );
D_DEBUG_DOMAIN( Core_GfxState,    "Core/GfxState",    "DirectFB Graphics Core State" );


DEFINE_MODULE_DIRECTORY( dfb_graphics_drivers, "gfxdrivers", DFB_GRAPHICS_DRIVER_ABI_VERSION );

/**********************************************************************************************************************/

static void dfb_gfxcard_find_driver( CoreDFB *core );
static void dfb_gfxcard_load_driver( void );

static void fill_tri( DFBTriangle *tri, CardState *state, bool accelerated );

/**********************************************************************************************************************/

typedef struct {
     int                      magic;

     /* amount of usable memory */
     unsigned int             videoram_length;
     unsigned int             auxram_length;
     unsigned int             auxram_offset;

     char                    *module_name;

     GraphicsDriverInfo       driver_info;
     GraphicsDeviceInfo       device_info;
     void                    *device_data;

     FusionProperty           lock;
     GraphicsDeviceLockFlags  lock_flags;

     /*
      * Points to the current state of the graphics card.
      */
     CardState               *state;
     FusionID                 holder; /* Fusion ID of state owner. */
} DFBGraphicsCoreShared;

struct __DFB_DFBGraphicsCore {
     int                        magic;

     CoreDFB                   *core;

     DFBGraphicsCoreShared     *shared;

     DirectModuleEntry         *module;
     const GraphicsDriverFuncs *driver_funcs;

     void                      *driver_data;
     void                      *device_data; /* copy of shared->device_data */

     CardCapabilities           caps;        /* local caps */
     CardLimitations            limits;      /* local limits */

     GraphicsDeviceFuncs        funcs;
};


DFB_CORE_PART( graphics_core, GraphicsCore );

/**********************************************************************************************************************/

static CoreGraphicsDevice *card;   /* FIXME */

/* Hook for registering additional screen(s) and layer(s) in app or lib initializing DirectFB. */
void (*__DFB_CoreRegisterHook)( CoreDFB *core, CoreGraphicsDevice *device, void *ctx ) = NULL;
void  *__DFB_CoreRegisterHookCtx = NULL;


/** public **/

static DFBResult
dfb_graphics_core_initialize( CoreDFB               *core,
                              DFBGraphicsCore       *data,
                              DFBGraphicsCoreShared *shared )
{
     DFBResult            ret;
     int                  videoram_length;
     int                  auxram_length;
     FusionSHMPoolShared *pool = dfb_core_shmpool( core );

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_initialize( %p, %p, %p )\n", core, data, shared );

     D_ASSERT( data != NULL );
     D_ASSERT( shared != NULL );


     card = data;   /* FIXME */

     data->core   = core;
     data->shared = shared;


     /* fill generic driver info */
     gGetDriverInfo( &shared->driver_info );

     /* fill generic device info */
     gGetDeviceInfo( &shared->device_info );

     if (!shared->device_info.limits.dst_max.w)
          shared->device_info.limits.dst_max.w = INT_MAX;

     if (!shared->device_info.limits.dst_max.h)
          shared->device_info.limits.dst_max.h = INT_MAX;

     /* Limit video ram length */
     videoram_length = dfb_system_videoram_length();
     if (videoram_length) {
          if (dfb_config->videoram_limit > 0 &&
              dfb_config->videoram_limit < videoram_length)
               shared->videoram_length = dfb_config->videoram_limit;
          else
               shared->videoram_length = videoram_length;
     }

     /* Limit auxiliary memory length (currently only AGP) */
     auxram_length = dfb_system_auxram_length();
     if (auxram_length) {
          if (dfb_config->agpmem_limit > 0 &&
              dfb_config->agpmem_limit < auxram_length)
               shared->auxram_length = dfb_config->agpmem_limit;
          else
               shared->auxram_length = auxram_length;
     }

     /* Build a list of available drivers. */
     direct_modules_explore_directory( &dfb_graphics_drivers );

     /* Load driver */
     if (dfb_system_caps() & CSCAPS_ACCELERATION)
          dfb_gfxcard_find_driver( core );

     if (data->driver_funcs) {
          const GraphicsDriverFuncs *funcs = data->driver_funcs;

          data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size );

          card->device_data   =
          shared->device_data = SHCALLOC( pool, 1, shared->driver_info.device_data_size );

          ret = funcs->InitDriver( card, &card->funcs,
                                   card->driver_data, card->device_data, core );
          if (ret) {
               SHFREE( pool, shared->device_data );
               SHFREE( pool, shared->module_name );
               D_FREE( card->driver_data );
               card = NULL;
               return ret;
          }

          ret = funcs->InitDevice( data, &shared->device_info,
                                   data->driver_data, data->device_data );
          if (ret) {
               funcs->CloseDriver( card, card->driver_data );
               SHFREE( pool, shared->device_data );
               SHFREE( pool, shared->module_name );
               D_FREE( card->driver_data );
               card = NULL;
               return ret;
          }

          if (data->funcs.EngineReset)
               data->funcs.EngineReset( data->driver_data, data->device_data );
     }

     D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n",
             shared->device_info.vendor, shared->device_info.name,
             shared->driver_info.version.major,
             shared->driver_info.version.minor, shared->driver_info.vendor );

     if (dfb_config->software_only) {
          if (data->funcs.CheckState) {
               data->funcs.CheckState = NULL;

               D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" );
          }
     }
     else {
          data->caps   = shared->device_info.caps;
          data->limits = shared->device_info.limits;
     }

     fusion_property_init( &shared->lock, dfb_core_world(core) );

     if (__DFB_CoreRegisterHook)
         __DFB_CoreRegisterHook( core, card, __DFB_CoreRegisterHookCtx );

     D_MAGIC_SET( data, DFBGraphicsCore );
     D_MAGIC_SET( shared, DFBGraphicsCoreShared );

     return DFB_OK;
}

static DFBResult
dfb_graphics_core_join( CoreDFB               *core,
                        DFBGraphicsCore       *data,
                        DFBGraphicsCoreShared *shared )
{
     DFBResult          ret;
     GraphicsDriverInfo driver_info;

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_join( %p, %p, %p )\n", core, data, shared );

     D_ASSERT( data != NULL );
     D_MAGIC_ASSERT( shared, DFBGraphicsCoreShared );

     card = data;   /* FIXME */

     data->core   = core;
     data->shared = shared;

     /* Initialize software rasterizer. */
     gGetDriverInfo( &driver_info );

     /* Build a list of available drivers. */
     direct_modules_explore_directory( &dfb_graphics_drivers );

     /* Load driver. */
     if (dfb_system_caps() & CSCAPS_ACCELERATION)
          dfb_gfxcard_load_driver();

     if (data->driver_funcs) {
          const GraphicsDriverFuncs *funcs = data->driver_funcs;

          data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size );

          data->device_data = shared->device_data;

          ret = funcs->InitDriver( card, &card->funcs,
                                   card->driver_data, card->device_data, core );
          if (ret) {
               D_FREE( data->driver_data );
               data = NULL;
               return ret;
          }
     }
     else if (shared->module_name) {
          D_ERROR( "DirectFB/Graphics: Could not load driver used by the running session!\n" );
          data = NULL;
          return DFB_UNSUPPORTED;
     }


     D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n",
             shared->device_info.vendor, shared->device_info.name,
             shared->driver_info.version.major,
             shared->driver_info.version.minor, shared->driver_info.vendor );

     if (dfb_config->software_only) {
          if (data->funcs.CheckState) {
               data->funcs.CheckState = NULL;

               D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" );
          }
     }
     else {
          data->caps   = shared->device_info.caps;
          data->limits = shared->device_info.limits;
     }

     D_MAGIC_SET( data, DFBGraphicsCore );

     return DFB_OK;
}

static DFBResult
dfb_graphics_core_shutdown( DFBGraphicsCore *data,
                            bool             emergency )
{
     DFBGraphicsCoreShared *shared;
     FusionSHMPoolShared   *pool = dfb_core_shmpool( data->core );

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " );

     D_MAGIC_ASSERT( data, DFBGraphicsCore );
     D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared );

     shared = data->shared;


     dfb_gfxcard_lock( GDLF_SYNC );

     if (data->driver_funcs) {
          const GraphicsDriverFuncs *funcs = data->driver_funcs;

          funcs->CloseDevice( data, data->driver_data, data->device_data );
          funcs->CloseDriver( data, data->driver_data );

          direct_module_unref( data->module );

          SHFREE( pool, card->device_data );
          D_FREE( card->driver_data );
     }

     fusion_property_destroy( &shared->lock );

     if (shared->module_name)
          SHFREE( pool, shared->module_name );


     D_MAGIC_CLEAR( data );
     D_MAGIC_CLEAR( shared );

     return DFB_OK;
}

static DFBResult
dfb_graphics_core_leave( DFBGraphicsCore *data,
                         bool             emergency )
{
     DFBGraphicsCoreShared *shared;

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " );

     D_MAGIC_ASSERT( data, DFBGraphicsCore );
     D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared );

     shared = data->shared;

     if (data->driver_funcs) {
          data->driver_funcs->CloseDriver( data, data->driver_data );

          direct_module_unref( data->module );

          D_FREE( data->driver_data );
     }


     D_MAGIC_CLEAR( data );

     return DFB_OK;
}

static DFBResult
dfb_graphics_core_suspend( DFBGraphicsCore *data )
{
     DFBGraphicsCoreShared *shared;

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_suspend( %p )\n", data );

     D_MAGIC_ASSERT( data, DFBGraphicsCore );
     D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared );

     shared = data->shared;

     dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE );

     return DFB_OK;
}

static DFBResult
dfb_graphics_core_resume( DFBGraphicsCore *data )
{
     DFBGraphicsCoreShared *shared;

     D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_resume( %p )\n", data );

     D_MAGIC_ASSERT( data, DFBGraphicsCore );
     D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared );

     shared = data->shared;

     dfb_gfxcard_unlock();

     return DFB_OK;
}

/**********************************************************************************************************************/

DFBResult
dfb_gfxcard_lock( GraphicsDeviceLockFlags flags )
{
     DFBResult              ret;
     DFBGraphicsCoreShared *shared;
     GraphicsDeviceFuncs   *funcs;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     shared = card->shared;
     funcs  = &card->funcs;

     if ( ((flags & GDLF_WAIT) ?
           fusion_property_purchase( &shared->lock ) :
           fusion_property_lease( &shared->lock )) )
          return DFB_FAILURE;

     if ((flags & GDLF_SYNC) && funcs->EngineSync) {
          ret = funcs->EngineSync( card->driver_data, card->device_data );
          if (ret) {
               if (funcs->EngineReset)
                    funcs->EngineReset( card->driver_data, card->device_data );

               shared->state = NULL;

               fusion_property_cede( &shared->lock );

               return ret;
          }
     }

     if ((shared->lock_flags & GDLF_RESET) && funcs->EngineReset)
          funcs->EngineReset( card->driver_data, card->device_data );

     if (shared->lock_flags & GDLF_INVALIDATE) {
          if (funcs->InvalidateState)
               funcs->InvalidateState( card->driver_data, card->device_data );
          shared->state = NULL;
     }

     shared->lock_flags = flags;

     return DFB_OK;
}

void
dfb_gfxcard_unlock( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     fusion_property_cede( &card->shared->lock );
}

void
dfb_gfxcard_holdup( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     fusion_property_holdup( &card->shared->lock );
}

/*
 * Signal beginning of a sequence of operations using this state.
 * Any number of states can be 'drawing'.
 */
void
dfb_gfxcard_start_drawing( CoreGraphicsDevice *device, CardState *state )
{
     D_ASSERT( device != NULL );
     D_MAGIC_ASSERT( state, CardState );

     if (device->funcs.StartDrawing)
          device->funcs.StartDrawing( device->driver_data, device->device_data, state );
}

/*
 * Signal end of sequence, i.e. destination surface is consistent again.
 */
void
dfb_gfxcard_stop_drawing( CoreGraphicsDevice *device, CardState *state )
{
     D_ASSERT( device != NULL );
     D_MAGIC_ASSERT( state, CardState );

     if (device->funcs.StopDrawing)
          device->funcs.StopDrawing( device->driver_data, device->device_data, state );
}

/*
 * This function returns non zero if acceleration is available
 * for the specific function using the given state.
 */
bool
dfb_gfxcard_state_check( CardState *state, DFBAccelerationMask accel )
{
     CoreSurface       *dst;
     CoreSurface       *src;
     CoreSurfaceBuffer *dst_buffer;
     CoreSurfaceBuffer *src_buffer;

     int cx2, cy2;

     D_ASSERT( card != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_MAGIC_ASSERT_IF( state->destination, CoreSurface );
     D_MAGIC_ASSERT_IF( state->source, CoreSurface );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x ) [%d,%d - %d,%d]\n",
                 __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) );

     D_ASSERT( state->clip.x2 >= state->clip.x1 );
     D_ASSERT( state->clip.y2 >= state->clip.y1 );
     D_ASSERT( state->clip.x1 >= 0 );
     D_ASSERT( state->clip.y1 >= 0 );

     if (DFB_BLITTING_FUNCTION(accel)) {
          D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x )  blitting %p -> %p\n", __FUNCTION__,
                      state, accel, state->source, state->destination );
     }
     else {
          D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x )  drawing -> %p\n", __FUNCTION__,
                      state, accel, state->destination );
     }

     if (state->clip.x1 < 0) {
          state->clip.x1   = 0;
          state->modified |= SMF_CLIP;
     }

     if (state->clip.y1 < 0) {
          state->clip.y1   = 0;
          state->modified |= SMF_CLIP;
     }

     D_DEBUG_AT( Core_GfxState, "  <- checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n",
                 state->checked, state->accel, state->modified, state->mod_hw );

     dst = state->destination;
     src = state->source;

     /* Destination may have been destroyed. */
     if (!dst) {
          D_BUG( "no destination" );
          return false;
     }

     /* Destination buffer may have been destroyed (suspended). i.e by a vt-switching */
     if (dst->num_buffers == 0 ) {
          return false;
     }

     /* Source may have been destroyed. */
     if (DFB_BLITTING_FUNCTION( accel )) {
          if (!src) {
               D_BUG( "no source" );
               return false;
          }

          /* Mask may have been destroyed. */
          if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR) && !state->source_mask) {
               D_BUG( "no mask" );
               return false;
          }
     }

     dst_buffer = dfb_surface_get_buffer( dst, state->to );
     D_MAGIC_ASSERT( dst_buffer, CoreSurfaceBuffer );

     D_ASSUME( state->clip.x2 < dst->config.size.w );
     D_ASSUME( state->clip.y2 < dst->config.size.h );

     cx2 = state->destination->config.size.w  - 1;
     cy2 = state->destination->config.size.h - 1;

     if (state->clip.x2 > cx2) {
          state->clip.x2 = cx2;

          if (state->clip.x1 > cx2)
               state->clip.x1 = cx2;

          state->modified |= SMF_CLIP;
     }

     if (state->clip.y2 > cy2) {
          state->clip.y2 = cy2;

          if (state->clip.y1 > cy2)
               state->clip.y1 = cy2;

          state->modified |= SMF_CLIP;
     }


     /*
      * If there's no CheckState function there's no acceleration at all.
      */
     if (!card->funcs.CheckState)
          return false;

     /*
      * Check if this function has been disabled temporarily.
      */
     if (state->disabled & accel)
          return false;

     /* If destination or blend functions have been changed... */
     if (state->modified & (SMF_DESTINATION | SMF_SRC_BLEND | SMF_DST_BLEND | SMF_RENDER_OPTIONS)) {
          /* ...force rechecking for all functions. */
          state->checked = DFXL_NONE;
     }
     else {
          /* If source/mask or blitting flags have been changed... */
          if (state->modified & (SMF_SOURCE | SMF_BLITTING_FLAGS | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS)) {
               /* ...force rechecking for all blitting functions. */
               state->checked &= ~DFXL_ALL_BLIT;
          }

          /* If drawing flags have been changed... */
          if (state->modified & SMF_DRAWING_FLAGS) {
               /* ...force rechecking for all drawing functions. */
               state->checked &= ~DFXL_ALL_DRAW;
          }
     }

     D_DEBUG_AT( Core_GfxState, "  -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n",
                 state->checked, state->accel, state->modified, state->mod_hw );

     /* If the function needs to be checked... */
     if (!(state->checked & accel)) {
          /* Unset unchecked functions. */
          state->accel &= state->checked;

          /* Call driver to (re)set the bit if the function is supported. */
          card->funcs.CheckState( card->driver_data, card->device_data, state, accel );

          /* Add the function to 'checked functions'. */
          state->checked |= accel;

          /* Add additional functions the driver might have checked, too. */
          state->checked |= state->accel;
     }

     D_DEBUG_AT( Core_GfxState, "  -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n",
                 state->checked, state->accel, state->modified, state->mod_hw );

     /* Move modification flags to the set for drivers. */
     state->mod_hw   |= state->modified;
     state->modified  = 0;

     /*
      * If back_buffer policy is 'system only' there's no acceleration
      * available.
      */
     if (dst_buffer->policy == CSP_SYSTEMONLY || /* Special check required if driver does not check itself. */
                                                 ( !(card->caps.flags & CCF_RENDEROPTS) &&
                                                    (state->render_options & DSRO_MATRIX) ))
     {
          /* Clear 'accelerated functions'. */
          state->accel   = DFXL_NONE;
          state->checked = DFXL_ALL;
     }
     else if (DFB_BLITTING_FUNCTION( accel )) {
          /*
           * If the front buffer policy of the source is 'system only'
           * no accelerated blitting is available.
           */
          src_buffer = dfb_surface_get_buffer( src, state->from );

          D_MAGIC_ASSERT( src_buffer, CoreSurfaceBuffer );

          if (src_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM)) {
               /* Clear 'accelerated blitting functions'. */
               state->accel   &= ~DFXL_ALL_BLIT;
               state->checked |=  DFXL_ALL_BLIT;
          }
     }

     D_DEBUG_AT( Core_GfxState, "  => checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n",
                 state->checked, state->accel, state->modified, state->mod_hw );

     /* Return whether the function bit is set. */
     return !!(state->accel & accel);
}

/*
 * This function returns non zero after successful locking the surface(s)
 * for access by hardware. Propagate state changes to driver.
 */
static bool
dfb_gfxcard_state_acquire( CardState *state, DFBAccelerationMask accel )
{
     DFBResult               ret;
     CoreSurface            *dst;
     CoreSurface            *src;
     DFBGraphicsCoreShared  *shared;
     CoreSurfaceAccessFlags  access = CSAF_WRITE;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     D_MAGIC_ASSERT( state, CardState );
     D_MAGIC_ASSERT_IF( state->destination, CoreSurface );
     D_MAGIC_ASSERT_IF( state->source, CoreSurface );

     dst    = state->destination;
     src    = state->source;
     shared = card->shared;

     /* find locking flags */
     if (DFB_BLITTING_FUNCTION( accel )) {
          if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL |
                                      DSBLIT_BLEND_COLORALPHA   |
                                      DSBLIT_DST_COLORKEY))
               access |= CSAF_READ;
     }
     else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY))
          access |= CSAF_READ;

     if (DFB_BLITTING_FUNCTION(accel)) {
          D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x )  blitting %p -> %p\n", __FUNCTION__,
                      state, accel, state->source, state->destination );
     }
     else {
          D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x )  drawing -> %p\n", __FUNCTION__,
                      state, accel, state->destination );
     }

     /* lock destination */
     ret = dfb_surface_lock_buffer( dst, state->to, CSAID_GPU, access, &state->dst );
     if (ret) {
          D_DEBUG_AT( Core_Graphics, "Could not lock destination for GPU access!\n" );
          return false;
     }

     /* if blitting... */
     if (DFB_BLITTING_FUNCTION( accel )) {
          /* ...lock source for reading */
          ret = dfb_surface_lock_buffer( src, state->from, CSAID_GPU, CSAF_READ, &state->src );
          if (ret) {
               D_DEBUG_AT( Core_Graphics, "Could not lock source for GPU access!\n" );
               dfb_surface_unlock_buffer( dst, &state->dst );
               return false;
          }

          state->flags |= CSF_SOURCE_LOCKED;

          /* if using a mask... */
          if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) {
               /* ...lock source mask for reading */
               ret = dfb_surface_lock_buffer( state->source_mask, state->from, CSAID_GPU, CSAF_READ, &state->src_mask );
               if (ret) {
                    D_DEBUG_AT( Core_Graphics, "Could not lock source mask for GPU access!\n" );
                    dfb_surface_unlock_buffer( src, &state->src );
                    dfb_surface_unlock_buffer( dst, &state->dst );
                    return false;
               }

               state->flags |= CSF_SOURCE_MASK_LOCKED;
          }
     }

     /*
      * Make sure that state setting with subsequent command execution
      * isn't done by two processes simultaneously.
      *
      * This will timeout if the hardware is locked by another party with
      * the first argument being true (e.g. DRI).
      */
     if (dfb_gfxcard_lock( GDLF_NONE )) {
          D_DERROR( ret, "Core/Graphics: Could not lock GPU!\n" );

          dfb_surface_unlock_buffer( dst, &state->dst );

          if (state->flags & CSF_SOURCE_LOCKED) {
               dfb_surface_unlock_buffer( src, &state->src );
               state->flags &= ~CSF_SOURCE_LOCKED;
          }

          /* if source mask got locked this value is true */
          if (state->flags & CSF_SOURCE_MASK_LOCKED) {
               dfb_surface_unlock_buffer( state->source_mask, &state->src_mask );

               state->flags &= ~CSF_SOURCE_MASK_LOCKED;
          }

          return false;
     }

     /* if we are switching to another state... */
     if (state != shared->state || state->fusion_id != shared->holder) {
          D_DEBUG_AT( Core_GfxState, "  -> switch from %p [%lu] to %p [%lu]\n",
                      shared->state, shared->holder, state, state->fusion_id );

          /* ...set all modification bits and clear 'set functions' */
          state->mod_hw |= SMF_ALL;
          state->set     = 0;

          shared->state  = state;
          shared->holder = state->fusion_id;
     }

     dfb_state_update( state, state->flags & (CSF_SOURCE_LOCKED | CSF_SOURCE_MASK_LOCKED) );

     D_DEBUG_AT( Core_GfxState, "  -> mod_hw 0x%08x, modified 0x%08x\n", state->mod_hw, state->modified );

     /* Move modification flags to the set for drivers. */
     state->mod_hw   |= state->modified;
     state->modified  = SMF_ALL;

     /*
      * If function hasn't been set or state is modified,
      * call the driver function to propagate the state changes.
      */
     D_DEBUG_AT( Core_GfxState, "  -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set );
     if (state->mod_hw || !(state->set & accel)) {
          card->funcs.SetState( card->driver_data, card->device_data,
                                &card->funcs, state, accel );

          D_DEBUG_AT( Core_GfxState, "  => mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set );
     }

     if (state->modified != SMF_ALL)
          D_ONCE( "USING OLD DRIVER! *** Use 'state->mod_hw' NOT 'modified'." );

     state->modified = 0;

    if (state->flags & CSF_DRAWING)
        D_ASSERT( state->device == card );
    else
    {
        if(card->funcs.BeginDraw)
            card->funcs.BeginDraw();

        state->flags  = (CardStateFlags)(state->flags | CSF_DRAWING);
        state->device = card;
    }

     return true;
}

/*
 * Unlock destination and possibly the source.
 */
static void
dfb_gfxcard_state_release( CardState *state )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( state->destination != NULL );

     /* start command processing if not already running */
     if (card->funcs.EmitCommands)
          card->funcs.EmitCommands( card->driver_data, card->device_data );

     /* Store the serial of the operation. */
#if FIXME_SC_2
     if (card->funcs.GetSerial) {
          card->funcs.GetSerial( card->driver_data, card->device_data, &state->serial );

          state->destination->back_buffer->video.serial = state->serial;
     }
#endif

      if (state->flags & CSF_DRAWING) {
           D_ASSERT( state->device != NULL );

           if (card->funcs.EndDraw)
                card->funcs.EndDraw();


           state->flags  = (CardStateFlags)(state->flags & ~CSF_DRAWING);
           state->device = NULL;
      }
      else
           D_ASSERT( state->device == NULL );

     if (card->funcs.GetSerial)
     {
          //update allocation HW fetch ID
          D_MAGIC_ASSERT( &state->dst, CoreSurfaceBufferLock );
          D_ASSERT(state->dst.allocation);
          D_MAGIC_ASSERT( state->dst.allocation, CoreSurfaceAllocation );
          card->funcs.GetSerial( card->driver_data, card->device_data, &state->serial );
          state->dst.allocation->gfxSerial = state->serial;
          //card->funcs.GetSerial( card->driver_data, card->device_data, &(state->dst.allocation->gfxSerial));
          if (state->flags & CSF_SOURCE_LOCKED)
          {
                D_MAGIC_ASSERT( &state->src, CoreSurfaceBufferLock );
                D_ASSERT(state->src.allocation);
                D_MAGIC_ASSERT( state->src.allocation, CoreSurfaceAllocation );
                state->src.allocation->gfxSerial = state->dst.allocation->gfxSerial;
          }
     }


     /* allow others to use the hardware */
     dfb_gfxcard_unlock();

     /* destination always gets locked during acquisition */
     dfb_surface_unlock_buffer( state->destination, &state->dst );

     /* if source got locked this value is true */
     if (state->flags & CSF_SOURCE_LOCKED) {
          dfb_surface_unlock_buffer( state->source, &state->src );

          state->flags &= ~CSF_SOURCE_LOCKED;
     }

     /* if source mask got locked this value is true */
     if (state->flags & CSF_SOURCE_MASK_LOCKED) {
          dfb_surface_unlock_buffer( state->source_mask, &state->src_mask );

          state->flags &= ~CSF_SOURCE_MASK_LOCKED;
     }
}

/** DRAWING FUNCTIONS **/

#define DFB_TRANSFORM(x, y, m, affine) \
do { \
     s32 _x, _y, _w; \
     if (affine) { \
          _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2] + 0x8000) >> 16; \
          _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5] + 0x8000) >> 16; \
     } \
     else { \
          _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2]); \
          _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5]); \
          _w = ((x) * (m)[6] + (y) * (m)[7] + (m)[8]); \
          if (!_w) { \
               _x = (_x < 0) ? -0x7fffffff : 0x7fffffff; \
               _y = (_y < 0) ? -0x7fffffff : 0x7fffffff; \
          } \
          else { \
               _x /= _w; \
               _y /= _w; \
          } \
     } \
     (x) = _x; \
     (y) = _y; \
} while (0)

DFBResult
dfb_gfxcard_fillrectangles( const DFBRectangle *rects, int num, CardState *state )
{
     D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, rects, num, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( rects != NULL );
     D_ASSERT( num > 0 );
     int          i = 0;
     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!(state->render_options & DSRO_MATRIX)) {
          while (num > 0) {
               if (dfb_rectangle_region_intersects( rects, &state->clip ))
                    break;

               rects++;
               num--;
          }
     }

     if (num > 0) {
          DFBRectangle rect;

          /* Check for acceleration and setup execution. */
          if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) &&
              dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE ))
          {
               /*
                * Now everything is prepared for execution of the
                * FillRectangle driver function.
                */
               for (; i<num; i++) {
                    if (!(state->render_options & DSRO_MATRIX) &&
                        !dfb_rectangle_region_intersects( &rects[i], &state->clip ))
                         continue;
                    if(state->drawingflags & (DSDRAW_COLOR_GRADIENT_X | DSDRAW_COLOR_GRADIENT_Y)
                        &&!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                             !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE )
                              &&!dfb_rectangle_region_contains(&rects[i], &state->clip))
                         break;

                    rect = rects[i];

                    if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) {
                         dfb_clip_rectangle( &state->clip, &rect );

                         if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h)
                              break;
                    }
                    else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                             !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ))
                         dfb_clip_rectangle( &state->clip, &rect );

                    if (!card->funcs.FillRectangle( card->driver_data,
                                                    card->device_data, &rect ))
                         break;
               }

               /* Release after state acquisition. */
               dfb_gfxcard_state_release( state );
          }

          if (i < num) {
               /* Use software fallback. */
               if (gAcquire( state, DFXL_FILLRECTANGLE )) {
                    if (!(state->render_options & DSRO_MATRIX)) {
                         for (; i<num; i++) {
                              rect = rects[i];

                              if (dfb_clip_rectangle( &state->clip, &rect ))
                                   gFillRectangle( state, &rect );
                         }
                    }
                    else if (state->matrix[1] == 0 && state->matrix[3] == 0) {
                         /* Scaled/Translated Rectangle. */
                         for (; i<num; i++) {
                              int x1, y1, x2, y2;

                              x1 = rects[i].x;    y1 = rects[i].y;
                              x2 = x1+rects[i].w; y2 = y1+rects[i].h;
                              DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                              if (x1 < x2) {
                                   rect.x = x1;
                                   rect.w = x2-x1;
                              } else {
                                   rect.x = x2;
                                   rect.w = x1-x2;
                              }
                              if (y1 < y2) {
                                   rect.y = y1;
                                   rect.h = y2-y1;
                              }
                              else {
                                   rect.y = y2;
                                   rect.h = y1-y2;
                              }

                              if (dfb_clip_rectangle( &state->clip, &rect ))
                                   gFillRectangle( state, &rect );
                         }
                    }
                    else {
                         /* Rotated rectangle. Split into triangles. */
                         for (; i<num; i++) {
                              DFBTriangle tri;

                              tri.x1 = rects[i].x;            tri.y1 = rects[i].y;
                              tri.x2 = rects[i].x+rects[i].w; tri.y2 = rects[i].y;
                              tri.x3 = rects[i].x+rects[i].w; tri.y3 = rects[i].y+rects[i].h;
                              DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix);

                              dfb_sort_triangle( &tri );
                              if (tri.y3 - tri.y1 > 0)
                                   fill_tri( &tri, state, false );

                              tri.x1 = rects[i].x;            tri.y1 = rects[i].y;
                              tri.x2 = rects[i].x+rects[i].w; tri.y2 = rects[i].y+rects[i].h;
                              tri.x3 = rects[i].x;            tri.y3 = rects[i].y+rects[i].h;
                              DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix);

                              dfb_sort_triangle( &tri );
                              if (tri.y3 - tri.y1 > 0)
                                   fill_tri( &tri, state, false );
                         }
                    }

                    gRelease( state );
               }
          }
     }

     /* Unlock after execution. */
     dfb_state_unlock( state );
     return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult
dfb_gfxcard_drawovals( const DFBOval *ovals, int num, CardState *state )
{
     int i = 0;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, ovals, num, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( ovals != NULL );
     D_ASSERT( num > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!(state->render_options & DSRO_MATRIX)) {
          while (num > 0) {
               if (dfb_rectangle_region_intersects( &ovals->oval_rect, &state->clip ))
                    break;

               ovals++;
               num--;
          }
     }

     if (num > 0) {

          DFBOval oval;

          /* Check for acceleration and setup execution. */
          if (dfb_gfxcard_state_check( state, DFXL_DRAWOVAL ) &&
              dfb_gfxcard_state_acquire( state, DFXL_DRAWOVAL ))
          {
               /*
                * Now everything is prepared for execution of the
                * DrawOval driver function.
                */
               for (; i<num; i++) {
                    if (!(state->render_options & DSRO_MATRIX) &&
                        !dfb_rectangle_region_intersects( &ovals[i].oval_rect, &state->clip ))
                         continue;

                    oval = ovals[i];

                    if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                          !D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWOVAL ) &&
                            dfb_clip_needed( &state->clip, &(oval.oval_rect) ) )
                         break;

                    if (!card->funcs.DrawOval( card->driver_data,
                                                    card->device_data, &oval ))
                         break;
               }
               /* Release after state acquisition. */
               dfb_gfxcard_state_release( state );
          }

          if (i < num) {
               /* Use software fallback. */
               if (gAcquire( state, DFXL_DRAWOVAL)) {
                    if (!(state->render_options & DSRO_MATRIX)) {
                         for (; i<num; i++) {
                              oval = ovals[i];
                              gDrawOval( state, &oval );
                         }
                    }
                    else if (state->matrix[1] == 0 && state->matrix[3] == 0) {
                         /* Scaled/Translated Oval. */
                         for (; i<num; i++) {
                              int x1, y1, x2, y2;

                              oval = ovals[i];

                              x1 = oval.oval_rect.x;    y1 = oval.oval_rect.y;
                              x2 = x1+oval.oval_rect.w; y2 = y1+oval.oval_rect.h;
                              DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                              if (x1 < x2) {
                                   oval.oval_rect.x = x1;
                                   oval.oval_rect.w = x2-x1;
                              } else {
                                   oval.oval_rect.x = x2;
                                   oval.oval_rect.w = x1-x2;
                              }
                              if (y1 < y2) {
                                   oval.oval_rect.y = y1;
                                   oval.oval_rect.h = y2-y1;
                              }
                              else {
                                   oval.oval_rect.y = y2;
                                   oval.oval_rect.h = y1-y2;
                              }

                              gDrawOval( state, &oval );
                         }
                    }
                    else {
                         /* Rotated oval. not supported yet. */
                         D_WARN( "rotation Oval not yet implemented" );
                    }

                    gRelease( state );
               }
          }
     }

     /* Unlock after execution. */
     dfb_state_unlock( state );
     return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

static void
build_clipped_rectangle_outlines( DFBRectangle    *rect,
                                  const DFBRegion *clip,
                                  DFBRectangle    *ret_outlines,
                                  int             *ret_num )
{
     DFBEdgeFlags edges = dfb_clip_edges( clip, rect );
     int          t     = (edges & DFEF_TOP ? 1 : 0);
     int          tb    = t + (edges & DFEF_BOTTOM ? 1 : 0);
     int          num   = 0;

     DFB_RECTANGLE_ASSERT( rect );

     D_ASSERT( ret_outlines != NULL );
     D_ASSERT( ret_num != NULL );

     if (edges & DFEF_TOP) {
          DFBRectangle *out = &ret_outlines[num++];

          out->x = rect->x;
          out->y = rect->y;
          out->w = rect->w;
          out->h = 1;
     }

     if (rect->h > t) {
          if (edges & DFEF_BOTTOM) {
               DFBRectangle *out = &ret_outlines[num++];

               out->x = rect->x;
               out->y = rect->y + rect->h - 1;
               out->w = rect->w;
               out->h = 1;
          }

          if (rect->h > tb) {
               if (edges & DFEF_LEFT) {
                    DFBRectangle *out = &ret_outlines[num++];

                    out->x = rect->x;
                    out->y = rect->y + t;
                    out->w = 1;
                    out->h = rect->h - tb;
               }

               if (rect->w > 1 || !(edges & DFEF_LEFT)) {
                    if (edges & DFEF_RIGHT) {
                         DFBRectangle *out = &ret_outlines[num++];

                         out->x = rect->x + rect->w - 1;
                         out->y = rect->y + t;
                         out->w = 1;
                         out->h = rect->h - tb;
                    }
               }
          }
     }

     *ret_num = num;
}

DFBResult dfb_gfxcard_drawrectangle( DFBRectangle *rect, CardState *state )
{
     DFBRectangle rects[4];
     bool         hw = false;
     int          i = 0, num = 0;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     DFB_RECTANGLE_ASSERT( rect );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS(rect), state );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!dfb_rectangle_region_intersects( rect, &state->clip )) {
          dfb_state_unlock( state );
          return DFB_OK;
     }

     if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) ||
         D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWRECTANGLE ) ||
         !dfb_clip_needed( &state->clip, rect ))
     {
          if (rect->w <= card->limits.dst_max.w && rect->h <= card->limits.dst_max.h &&
              dfb_gfxcard_state_check( state, DFXL_DRAWRECTANGLE ) &&
              dfb_gfxcard_state_acquire( state, DFXL_DRAWRECTANGLE ))
          {
               hw = card->funcs.DrawRectangle( card->driver_data,
                                               card->device_data, rect );

               dfb_gfxcard_state_release( state );
          }
     }

     if (!hw && !(state->render_options & DSRO_MATRIX)) {
          build_clipped_rectangle_outlines( rect, &state->clip, rects, &num );

          if (!num) {
               dfb_state_unlock( state );
               return DFB_OK;
          }

          if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) &&
              dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE ))
          {
               for (; i<num; i++) {
                    hw = rects[i].w <= card->limits.dst_max.w && rects[i].h <= card->limits.dst_max.h
                         && card->funcs.FillRectangle( card->driver_data,
                                                       card->device_data, &rects[i] );
                    if (!hw)
                         break;
               }

               dfb_gfxcard_state_release( state );
          }
     }

     if (!hw) {
          if (!(state->render_options & DSRO_MATRIX)) {
               if (gAcquire( state, DFXL_FILLRECTANGLE )) {
                    for (; i<num; i++)
                         gFillRectangle( state, &rects[i] );

                    gRelease( state );
               }
          }
          else {
                if (gAcquire( state, DFXL_DRAWLINE )) {
                    DFBRegion line;
                    int       x1, x2, x3, x4;
                    int       y1, y2, y3, y4;

                    x1 = rect->x;         y1 = rect->y;
                    x2 = rect->x+rect->w; y2 = rect->y;
                    x3 = rect->x+rect->w; y3 = rect->y+rect->h;
                    x4 = rect->x;         y4 = rect->y+rect->h;
                    DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(x3, y3, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(x4, y4, state->matrix, state->affine_matrix);

                    line = (DFBRegion) { x1, y1, x2, y2 };
                    if (dfb_clip_line( &state->clip, &line ))
                         gDrawLine( state, &line );

                    line = (DFBRegion) { x2, y2, x3, y3 };
                    if (dfb_clip_line( &state->clip, &line ))
                         gDrawLine( state, &line );

                    line = (DFBRegion) { x3, y3, x4, y4 };
                    if (dfb_clip_line( &state->clip, &line ))
                         gDrawLine( state, &line );

                    line = (DFBRegion) { x4, y4, x1, y1 };
                    if (dfb_clip_line( &state->clip, &line ))
                         gDrawLine( state, &line );

                    gRelease( state );
               }
          }
     }

     dfb_state_unlock( state );

     return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult dfb_gfxcard_drawlines( DFBRegion *lines, int num_lines, CardState *state )
{
     int i = 0;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, lines, num_lines, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( lines != NULL );
     D_ASSERT( num_lines > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_DRAWLINE ) &&
         dfb_gfxcard_state_acquire( state, DFXL_DRAWLINE ))
     {
          for (; i<num_lines; i++) {
               if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                   !D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWLINE ) &&
                   !dfb_clip_line( &state->clip, &lines[i] ))
                    continue;

               if (!card->funcs.DrawLine( card->driver_data,
                                          card->device_data, &lines[i] ))
                    break;
          }

          dfb_gfxcard_state_release( state );
     }

     if (i < num_lines) {
          if (gAcquire( state, DFXL_DRAWLINE )) {
               for (; i<num_lines; i++) {
                    if (state->render_options & DSRO_MATRIX) {
                         DFB_TRANSFORM(lines[i].x1, lines[i].y1, state->matrix, state->affine_matrix);
                         DFB_TRANSFORM(lines[i].x2, lines[i].y2, state->matrix, state->affine_matrix);
                    }

                    if (dfb_clip_line( &state->clip, &lines[i] ))
                         gDrawLine( state, &lines[i] );
               }

               gRelease( state );
          }
     }

     dfb_state_unlock( state );
     return (i==num_lines)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult dfb_gfxcard_fillspans( int y, DFBSpan *spans, int num_spans, CardState *state )
{
     int i = 0;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %d, %p [%d], %p )\n", __FUNCTION__, y, spans, num_spans, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( spans != NULL );
     D_ASSERT( num_spans > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) &&
         dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE ))
     {
          for (; i<num_spans; i++) {
               DFBRectangle rect = { spans[i].x, y + i, spans[i].w, 1 };

               if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) {
                    if (!dfb_clip_rectangle( &state->clip, &rect ))
                         continue;

                    if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h)
                         break;
               }
               else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                        !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ) &&
                        !dfb_clip_rectangle( &state->clip, &rect ))
                         continue;

               if (!card->funcs.FillRectangle( card->driver_data,
                                               card->device_data, &rect ))
                    break;
          }

          dfb_gfxcard_state_release( state );
     }

     if (i < num_spans) {
          if (gAcquire( state, DFXL_FILLRECTANGLE )) {
               for (; i<num_spans; i++) {
                    DFBRectangle rect = { spans[i].x, y + i, spans[i].w, 1 };

                    if (state->render_options & DSRO_MATRIX) {
                         if (state->matrix[1] == 0 && state->matrix[3] == 0) {
                              int x1, y1, x2, y2;

                              x1 = rect.x;    y1 = rect.y;
                              x2 = x1+rect.w; y2 = y1+rect.h;
                              DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                              if (x1 < x2) {
                                   rect.x = x1;
                                   rect.w = x2-x1;
                              } else {
                                   rect.x = x2;
                                   rect.w = x1-x2;
                              }
                              if (y1 < y2) {
                                   rect.y = y1;
                                   rect.h = y2-y1;
                              }
                              else {
                                   rect.y = y2;
                                   rect.h = y1-y2;
                              }

                              if (dfb_clip_rectangle( &state->clip, &rect ))
                                   gFillRectangle( state, &rect );
                         }
                         else {
                              DFBTriangle tri;

                              tri.x1 = rect.x;        tri.y1 = rect.y;
                              tri.x2 = rect.x+rect.w; tri.y2 = rect.y;
                              tri.x3 = rect.x+rect.w; tri.y3 = rect.y+rect.h;
                              DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix);

                              dfb_sort_triangle( &tri );
                              if (tri.y3 - tri.y1 > 0)
                                   fill_tri( &tri, state, false );

                              tri.x1 = rect.x;        tri.y1 = rect.y;
                              tri.x2 = rect.x+rect.w; tri.y2 = rect.y+rect.h;
                              tri.x3 = rect.x;        tri.y3 = rect.y+rect.h;
                              DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix);

                              dfb_sort_triangle( &tri );
                              if (tri.y3 - tri.y1 > 0)
                                   fill_tri( &tri, state, false );
                         }
                    }
                    else {
                         if (dfb_clip_rectangle( &state->clip, &rect ))
                              gFillRectangle( state, &rect );
                    }
               }

               gRelease( state );
          }
     }

     dfb_state_unlock( state );
     return (i==num_spans)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}


typedef struct {
   int xi;
   int xf;
   int mi;
   int mf;
   int _2dy;
} DDA;

#define SETUP_DDA(xs,ys,xe,ye,dda)         \
     do {                                  \
          int dx = xe - xs;                \
          int dy = ye - ys;                \
          dda.xi = xs;                     \
          if (dy != 0) {                   \
               dda.mi = dx / dy;           \
               dda.mf = 2*(dx % dy);       \
               dda.xf = -dy;               \
               dda._2dy = 2 * dy;          \
               if (dda.mf < 0) {           \
                    dda.mf += 2 * ABS(dy); \
                    dda.mi--;              \
               }                           \
          }                                \
          else {                           \
               dda.mi = 0;                 \
               dda.mf = 0;                 \
               dda.xf = 0;                 \
               dda._2dy = 0;               \
          }                                \
     } while (0)


#define INC_DDA(dda)                       \
     do {                                  \
          dda.xi += dda.mi;                \
          dda.xf += dda.mf;                \
          if (dda.xf > 0) {                \
               dda.xi++;                   \
               dda.xf -= dda._2dy;         \
          }                                \
     } while (0)


/**
 *  render a triangle using two parallel DDA's
 */
static void
fill_tri( DFBTriangle *tri, CardState *state, bool accelerated )
{
     int y, yend;
     DDA dda1 = { .xi = 0 }, dda2 = { .xi = 0 };
     int clip_x1 = state->clip.x1;
     int clip_x2 = state->clip.x2;

     D_MAGIC_ASSERT( state, CardState );

     y = tri->y1;
     yend = tri->y3;

     if (yend > state->clip.y2)
          yend = state->clip.y2;

     SETUP_DDA(tri->x1, tri->y1, tri->x3, tri->y3, dda1);
     SETUP_DDA(tri->x1, tri->y1, tri->x2, tri->y2, dda2);

     while (y <= yend) {
          DFBRectangle rect;

          if (y == tri->y2) {
               if (tri->y2 == tri->y3)
                    return;
               SETUP_DDA(tri->x2, tri->y2, tri->x3, tri->y3, dda2);
          }

          rect.w = ABS(dda1.xi - dda2.xi);
          rect.x = MIN(dda1.xi, dda2.xi);

          if (clip_x2 < rect.x + rect.w)
               rect.w = clip_x2 - rect.x + 1;

          if (rect.w > 0) {
               if (clip_x1 > rect.x) {
                    rect.w -= (clip_x1 - rect.x);
                    rect.x = clip_x1;
               }
               rect.y = y;
               rect.h = 1;

               if (rect.w > 0 && rect.y >= state->clip.y1) {
                    if (accelerated)
                         card->funcs.FillRectangle( card->driver_data,
                                                    card->device_data, &rect );
                    else
                         gFillRectangle( state, &rect );
               }
          }

          INC_DDA(dda1);
          INC_DDA(dda2);

          y++;
     }
}


DFBResult dfb_gfxcard_filltriangles( const DFBTriangle *tris, int num, CardState *state )
{
     bool hw = false;
     int  i  = 0;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( tris != NULL );
     D_ASSERT( num > 0 );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, tris, num, state );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_FILLTRIANGLE ) &&
         dfb_gfxcard_state_acquire( state, DFXL_FILLTRIANGLE ))
     {
          if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRIANGLE ))
          {
               DFBPoint p[6];
               int      n;

               for (; i < num; i++) {
                    /* FIXME: DSRO_MATRIX. */
                    if (dfb_clip_triangle( &state->clip, &tris[i], p, &n )) {
                         DFBTriangle tri;
                         int         j;

                         tri.x1 = p[0].x; tri.y1 = p[0].y;
                         tri.x2 = p[1].x; tri.y2 = p[1].y;
                         tri.x3 = p[2].x; tri.y3 = p[2].y;
                         hw = card->funcs.FillTriangle( card->driver_data,
                                                        card->device_data, &tri );
                         if (!hw)
                              break;

                         /* FIXME: return value. */
                         for (j = 3; j < n; j++) {
                              tri.x1 = p[0].x;   tri.y1 = p[0].y;
                              tri.x2 = p[j-1].x; tri.y2 = p[j-1].y;
                              tri.x3 = p[j].x;   tri.y3 = p[j].y;
                              card->funcs.FillTriangle( card->driver_data,
                                                        card->device_data, &tri );
                         }
                    }
               }
          }
          else {
               for (; i < num; i++) {
                    DFBTriangle tri = tris[i];

                    hw = card->funcs.FillTriangle( card->driver_data,
                                                   card->device_data, &tri );
                    if (!hw)
                         break;
               }

          }

          dfb_gfxcard_state_release( state );
     }

     if (!hw && i < num) {
          /* otherwise use the spanline rasterizer (fill_tri)
             and fill the triangle using a rectangle for each spanline */

          /* try hardware accelerated rectangle filling */
          if (!(card->caps.flags & CCF_NOTRIEMU) &&
              dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) &&
              dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE ))
          {
               for (; i < num; i++) {
                    DFBTriangle tri = tris[i];

                    dfb_sort_triangle( &tri );

                    if (tri.y3 - tri.y1 > 0)
                         fill_tri( &tri, state, true );
               }

               dfb_gfxcard_state_release( state );
          }
          else if (gAcquire( state, DFXL_FILLRECTANGLE )) {
               for (; i < num; i++) {
                    DFBTriangle tri = tris[i];

                    if (state->render_options & DSRO_MATRIX) {
                         DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix);
                         DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix);
                         DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix);
                    }

                    dfb_sort_triangle( &tri );

                    if (tri.y3 - tri.y1 > 0)
                         fill_tri( &tri, state, false );
               }

               gRelease( state );
          }
     }

     dfb_state_unlock( state );
     return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

static void
clip_blit_rotated( DFBRectangle *srect, DFBRectangle *drect, const DFBRegion *clip, DFBSurfaceBlittingFlags flags )
{
     DFBRegion dest    = DFB_REGION_INIT_FROM_RECTANGLE( drect );
     DFBRegion clipped = dest;

     if (flags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) {
          D_ASSERT( srect->w == drect->h );
          D_ASSERT( srect->h == drect->w );
     }
     else {
          D_ASSERT( srect->w == drect->w );
          D_ASSERT( srect->h == drect->h );
     }

     dfb_region_region_intersect( &clipped, clip );
     dfb_rectangle_from_region( drect, &clipped );

     if (flags & DSBLIT_ROTATE90) {
          srect->x += dest.y2 - clipped.y2;
          srect->y += clipped.x1 - dest.x1;
          srect->w  = drect->h;
          srect->h  = drect->w;

          D_DEBUG_AT( Core_GraphicsOps, "  => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (90)\n",
                      DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) );
     }
     else if (flags & DSBLIT_ROTATE180) {
          srect->x += dest.x2 - clipped.x2;
          srect->y += dest.y2 - clipped.y2;
          srect->w  = drect->w;
          srect->h  = drect->h;

          D_DEBUG_AT( Core_GraphicsOps, "  => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (180)\n",
                      DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) );
     }
     else if (flags & DSBLIT_ROTATE270) {
          srect->x += clipped.y1 - dest.y1;
          srect->y += dest.x2 - clipped.x2;
          srect->w  = drect->h;
          srect->h  = drect->w;

          D_DEBUG_AT( Core_GraphicsOps, "  => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (270)\n",
                      DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) );
     }
     else {
          srect->x += clipped.x1 - dest.x1;
          srect->y += clipped.y1 - dest.y1;
          srect->w  = drect->w;
          srect->h  = drect->h;

          D_DEBUG_AT( Core_GraphicsOps, "  => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n",
                      DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) );
     }
}



DFBResult dfb_gfxcard_blit( DFBRectangle *rect, int dx, int dy, CardState *state )
{
     bool         hw    = false;
     DFBRectangle drect = { dx, dy, rect->w, rect->h };
     DFBResult result = DFB_OK;

     if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270))
          D_UTIL_SWAP( drect.w, drect.h );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d, %p )\n",
                 __FUNCTION__, DFB_RECTANGLE_VALS(rect), DFB_RECTANGLE_VALS(&drect), state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( state->source != NULL );
     D_ASSERT( rect != NULL );
     D_ASSERT( rect->x >= 0 );
     D_ASSERT( rect->y >= 0 );
     D_ASSERT( rect->x < state->source->config.size.w );
     D_ASSERT( rect->y < state->source->config.size.h );
     D_ASSERT( rect->x + rect->w - 1 < state->source->config.size.w );
     D_ASSERT( rect->y + rect->h - 1 < state->source->config.size.h );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!(state->render_options & DSRO_MATRIX) &&
         !dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y ))
     {
          /* no work at all */
          dfb_state_unlock( state );
          return DFB_OK;
     }

     if (dfb_gfxcard_state_check( state, DFXL_BLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_BLIT ))
     {
          if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT ))
          	{
               clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags );
          	}


          hw = card->funcs.Blit( card->driver_data, card->device_data, rect, drect.x, drect.y );

          dfb_gfxcard_state_release( state );
     }


     if (!hw) {
          if (state->render_options & DSRO_MATRIX) {
               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0) {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return DFB_UNSUPPORTED;
               }

               if (gAcquire( state, DFXL_STRETCHBLIT )) {
                    DFBRectangle drect;
                    int          x1, y1, x2, y2;

                    x1 = dx;         y1 = dy;
                    x2 = dx+rect->w; y2 = dy+rect->h;
                    DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                    drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 };
                    if (dfb_clip_blit_precheck( &state->clip,
                                                drect.w, drect.h, drect.x, drect.y ))
                         gStretchBlit( state, rect, &drect );

                    gRelease( state );
               }
               else
                   result = DFB_UNSUPPORTED;
          }
          else {
               if (gAcquire( state, DFXL_BLIT )) {
                    clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags );

                    gBlit( state, rect, drect.x, drect.y );

                    gRelease( state );
               }
               else
                   result = DFB_UNSUPPORTED;
          }
     }

     dfb_state_unlock( state );
     return result;
}

DFBResult dfb_gfxcard_trapezoidblit(DFBRectangle *srect, DFBTrapezoid *trapezoid, CardState *state )
{
     bool         hw    = false;
     DFBResult result = DFB_OK;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d ->, %p )\n",
                 __FUNCTION__, DFB_RECTANGLE_VALS(srect),  state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( state->source != NULL );
     D_ASSERT( trapezoid != NULL );
     D_ASSERT( trapezoid->x0 >= 0 );
     D_ASSERT( trapezoid->y0 >= 0 );
     D_ASSERT( trapezoid->x1 >= 0 );
     D_ASSERT( trapezoid->y1 >= 0 );
     D_ASSERT( trapezoid->top_edge_width > 0 );
     D_ASSERT( trapezoid->bottom_edge_width > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_TRAPEZOID_BLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_TRAPEZOID_BLIT ))
     {
         DFBBoolean bhwblit = DFB_TRUE;
          if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_TRAPEZOID_BLIT ))
                  bhwblit = dfb_clip_trapezoid_precheck(&state->clip, trapezoid);

          if(bhwblit)
               hw = card->funcs.BlitTrapezoid( card->driver_data, card->device_data, srect, trapezoid);

          dfb_gfxcard_state_release( state );
     }

     if (!hw)
    {
          DFBTrapezoid dtrapezoid = *trapezoid;
          int x, y;

          if (state->render_options & DSRO_MATRIX)
          {
               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0)
               {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return DFB_UNSUPPORTED;
               }
               else
               {
                    DFB_TRANSFORM(dtrapezoid.x0, dtrapezoid.y0, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(dtrapezoid.x1, dtrapezoid.y1, state->matrix, state->affine_matrix);
                    if(dtrapezoid.horiz_direct)
                    {
                         x= trapezoid->x0+trapezoid->top_edge_width;
                         y = trapezoid->y0;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.top_edge_width = x-dtrapezoid.x0;

                         x= trapezoid->x1+trapezoid->bottom_edge_width;
                         y = trapezoid->y1;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.bottom_edge_width = x-dtrapezoid.x1;
                    }
                    else
                    {
                         x= trapezoid->x0;
                         y = trapezoid->y0+trapezoid->top_edge_width;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.top_edge_width = y-dtrapezoid.y0;

                         x= trapezoid->x1;
                         y = trapezoid->y1+trapezoid->bottom_edge_width;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.bottom_edge_width = y-dtrapezoid.y1;
                    }


             }
          }

         if (gAcquire( state, DFXL_TRAPEZOID_BLIT ))
         {
              gTrapezoidBlit( state, srect, &dtrapezoid );
              gRelease( state );
         }
         else
            result = DFB_UNSUPPORTED;
     }

     dfb_state_unlock( state );
     return result;
}

DFBResult dfb_gfxcard_filltrapezoid(DFBTrapezoid *trapezoid, CardState *state )
{
     bool         hw    = false;
     DFBResult result = DFB_OK;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d ->, %p )\n",
                 __FUNCTION__, trapezoid->x0, trapezoid->y0, trapezoid->x1, trapezoid->y1,  state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( state->source != NULL );
     D_ASSERT( trapezoid != NULL );
     D_ASSERT( trapezoid->x0 >= 0 );
     D_ASSERT( trapezoid->y0 >= 0 );
     D_ASSERT( trapezoid->x1 >= 0 );
     D_ASSERT( trapezoid->y1 >= 0 );
     D_ASSERT( trapezoid->top_edge_width > 0 );
     D_ASSERT( trapezoid->bottom_edge_width > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_FILLTRAPEZOID ) &&
         dfb_gfxcard_state_acquire( state, DFXL_FILLTRAPEZOID ))
     {
         DFBBoolean bhwblit = DFB_TRUE;
          if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRAPEZOID ))
                  bhwblit = dfb_clip_trapezoid_precheck(&state->clip, trapezoid);

          if(bhwblit)
               hw = card->funcs.FillTrapezoid( card->driver_data, card->device_data, trapezoid);

          dfb_gfxcard_state_release( state );
     }

     if (!hw)
     {
          DFBTrapezoid dtrapezoid = *trapezoid;

          if (state->render_options & DSRO_MATRIX)
          {
               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0)
              {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return DFB_UNIMPLEMENTED;
               }
               else
               {
                    int x, y;

                    DFB_TRANSFORM(dtrapezoid.x0, dtrapezoid.y0, state->matrix, state->affine_matrix);
                    DFB_TRANSFORM(dtrapezoid.x1, dtrapezoid.y1, state->matrix, state->affine_matrix);
                    if(dtrapezoid.horiz_direct)
                    {
                         x= trapezoid->x0+trapezoid->top_edge_width;
                         y = trapezoid->y0;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.top_edge_width = x-dtrapezoid.x0;

                         x= trapezoid->x1+trapezoid->bottom_edge_width;
                         y = trapezoid->y1;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.bottom_edge_width = x-dtrapezoid.x1;
                    }
                    else
                    {
                         x= trapezoid->x0;
                         y = trapezoid->y0+trapezoid->top_edge_width;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.top_edge_width = y-dtrapezoid.y0;

                         x= trapezoid->x1;
                         y = trapezoid->y1+trapezoid->bottom_edge_width;
                         DFB_TRANSFORM(x, y, state->matrix, state->affine_matrix);
                         dtrapezoid.bottom_edge_width = y-dtrapezoid.y1;
                    }

             }
         }

         if (gAcquire( state, DFXL_FILLTRIANGLE ))
         {
                   DFBTriangle tri;
                   if(dtrapezoid.horiz_direct)
                   {
                         tri.x1 = dtrapezoid.x0; tri.y1 = dtrapezoid.y0;
                         tri.x2 = dtrapezoid.x0+trapezoid->top_edge_width ; tri.y2 = dtrapezoid.y0;
                         tri.x3 = dtrapezoid.x1+trapezoid->bottom_edge_width ; tri.y3 = dtrapezoid.y1;

                         dfb_sort_triangle( &tri );

                         if (tri.y3 - tri.y1 > 0)
                                fill_tri( &tri, state, false );

                         tri.x1 = dtrapezoid.x0; tri.y1 = dtrapezoid.y0;
                         tri.x2 = dtrapezoid.x1+trapezoid->bottom_edge_width; tri.y2 = dtrapezoid.y1;
                         tri.x3 = dtrapezoid.x1; tri.y3 = dtrapezoid.y1;

                         dfb_sort_triangle( &tri );

                         if (tri.y3 - tri.y1 > 0)
                                fill_tri( &tri, state, false );
                    }
                    else
                    {
                         tri.x1 = dtrapezoid.x0; tri.y1 = dtrapezoid.y0;
                         tri.x2 = dtrapezoid.x1; tri.y2 = dtrapezoid.y1;
                         tri.x3 = dtrapezoid.x1; tri.y3 = dtrapezoid.y1+trapezoid->bottom_edge_width ;

                         dfb_sort_triangle( &tri );

                         if (tri.y3 - tri.y1 > 0)
                                 fill_tri( &tri, state, false );

                         tri.x1 = dtrapezoid.x0; tri.y1 = dtrapezoid.y0;
                         tri.x2 = dtrapezoid.x1; tri.y2 = dtrapezoid.y1+trapezoid->bottom_edge_width;
                         tri.x3 = dtrapezoid.x0; tri.y3 = dtrapezoid.y0+trapezoid->top_edge_width ;

                         dfb_sort_triangle( &tri );

                         if (tri.y3 - tri.y1 > 0)
                                  fill_tri( &tri, state, false );
                     }

                gRelease( state );
          }
          else
            result = DFB_UNSUPPORTED;
     }

     dfb_state_unlock( state );
	 return result;
}

DFBResult dfb_gfxcard_batchblit( DFBRectangle *rects, DFBPoint *points,
                            int num, CardState *state )
{
     int i = 0;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p [%d], %p )\n", __FUNCTION__, rects, points, num, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( rects != NULL );
     D_ASSERT( points != NULL );
     D_ASSERT( num > 0 );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (dfb_gfxcard_state_check( state, DFXL_BLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_BLIT ))
     {
          for (; i<num; i++) {
               if ((state->render_options & DSRO_MATRIX) ||
                   dfb_clip_blit_precheck( &state->clip,
                                           rects[i].w, rects[i].h,
                                           points[i].x, points[i].y ))
               {
                    if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                        !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT ))
                    	{
                         dfb_clip_blit( &state->clip, &rects[i],
                                        &points[i].x, &points[i].y );
                    	}


                    if (!card->funcs.Blit( card->driver_data, card->device_data,
                                           &rects[i], points[i].x, points[i].y ))
                         break;
               }
          }

          dfb_gfxcard_state_release( state );
     }


     if (i < num) {
          if (state->render_options & DSRO_MATRIX) {
               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0) {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
               }

               if (gAcquire( state, DFXL_STRETCHBLIT )) {
                    for (; i<num; i++) {
                         DFBRectangle drect;
                         int          x1, y1, x2, y2;

                         x1 = points[i].x;   y1 = points[i].y;
                         x2 = x1+rects[i].w; y2 = y1+rects[i].h;
                         DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                         DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                         drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 };
                         if (dfb_clip_blit_precheck( &state->clip,
                                                     drect.w, drect.h, drect.x, drect.y ))
                              gStretchBlit( state, &rects[i], &drect );
                    }

                    gRelease( state );
               }
          }
          else {
               if (gAcquire( state, DFXL_BLIT )) {
                    for (; i<num; i++) {
                         if (dfb_clip_blit_precheck( &state->clip,
                                                     rects[i].w, rects[i].h,
                                                     points[i].x, points[i].y ))
                         {
                              dfb_clip_blit( &state->clip, &rects[i],
                                             &points[i].x, &points[i].y );

                              gBlit( state, &rects[i], points[i].x, points[i].y );
                         }
                    }

                    gRelease( state );
               }
          }
     }

     dfb_state_unlock( state );
     return (i==num)?DFB_OK:(i==0)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult dfb_gfxcard_tileblit( DFBRectangle *rect, int dx1, int dy1, int dx2, int dy2,
                           CardState *state )
{
     int           x, y;
     int           odx;
     DFBRectangle  srect;
     DFBRegion    *clip;
     bool   bblit_some;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %d,%d, %p )\n", __FUNCTION__, dx1, dy1, dx2, dy2, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( rect != NULL );

     /* If called with an invalid rectangle, the algorithm goes into an
        infinite loop. This should never happen but it's safer to check. */
     D_ASSERT( rect->w >= 1 );
     D_ASSERT( rect->h >= 1 );

     if(rect->w==1 && rect->h==1)
     {
        /*
        Patch: to accelerate "1x1" tile pattern with stretchblt. If tileblt
        with 1x1 pattern is peformed, it gets really slow on big  destination rectangle.
        (For example, http://ditu.baidu.com has "1x1" backgroud with repeat feature)
        */
        DFBRectangle dst_rect = {dx1, dy1, dx2-dx1+1, dy2-dy1+1};
        return dfb_gfxcard_stretchblit(rect, &dst_rect, state);
     }

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     clip = &state->clip;

     /* Check if anything is drawn at all. */
     if (!(state->render_options & DSRO_MATRIX) &&
         !dfb_clip_blit_precheck( clip, dx2-dx1+1, dy2-dy1+1, dx1, dy1 )) {
          dfb_state_unlock( state );
          return DFB_OK;
     }

     /* Remove clipped tiles. */
     if (dx1 < clip->x1) {
          int outer = clip->x1 - dx1;

          dx1 += outer - (outer % rect->w);
     }

     if (dy1 < clip->y1) {
          int outer = clip->y1 - dy1;

          dy1 += outer - (outer % rect->h);
     }

     if (dx2 > clip->x2) {
          int outer = clip->x2 - dx2;

          dx2 -= outer - (outer % rect->w);
     }

     if (dy2 > clip->y2) {
          int outer = clip->y2 - dy2;

          dy2 -= outer - (outer % rect->h);
     }

     odx = dx1;

     bblit_some = false;

     if (dfb_gfxcard_state_check( state, DFXL_BLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_BLIT )) {
          bool hw = true;

          for (; dy1 < dy2; dy1 += rect->h) {
               for (; dx1 < dx2; dx1 += rect->w) {

                    if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 ))
                         continue;

                    x = dx1;
                    y = dy1;
                    srect = *rect;

                    if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
                        !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT ))
                    	{
                         dfb_clip_blit( clip, &srect, &x, &y );
                    	}
					    else
					    {
					     //optimazation for hw clip ,use sw clip to descrease  the GE overload
					     dfb_clip_blit( clip, &srect, &x, &y );
					    }

                    hw = card->funcs.Blit( card->driver_data,
                                           card->device_data, &srect, x, y );
                    if (!hw)
                         break;
                    bblit_some = true;
               }
               if (!hw)
                    break;
               dx1 = odx;
          }

          dfb_gfxcard_state_release( state );
     }

     if (dy1 < dy2) {
          if (state->render_options & DSRO_MATRIX) {
               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0) {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return bblit_some?DFB_INCOMPLETE:DFB_UNSUPPORTED;
               }

               if (gAcquire( state, DFXL_STRETCHBLIT )) {
                    for (; dy1 < dy2; dy1 += rect->h) {
                         for (; dx1 < dx2; dx1 += rect->w) {
                              DFBRectangle drect;
                              int          x1, y1, x2, y2;

                              x1 = dx1;         y1 = dy1;
                              x2 = dx1+rect->w; y2 = dy1+rect->h;
                              DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
                              DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);

                              drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 };
                              if (dfb_clip_blit_precheck( &state->clip,
                                                          drect.w, drect.h, drect.x, drect.y ))
                              {
                                   gStretchBlit( state, rect, &drect );
                                   bblit_some = true;
                              }
                         }
                         dx1 = odx;
                    }

                    gRelease( state );
               }
          }
          else {
               if (gAcquire( state, DFXL_BLIT )) {
                    for (; dy1 < dy2; dy1 += rect->h) {
                         for (; dx1 < dx2; dx1 += rect->w) {

                              if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 ))
                                   continue;

                              x = dx1;
                              y = dy1;
                              srect = *rect;

                              dfb_clip_blit( clip, &srect, &x, &y );

                              gBlit( state, &srect, x, y );
                              bblit_some = true;
                         }
                         dx1 = odx;
                    }

                    gRelease( state );
               }
          }
     }

     dfb_state_unlock( state );
     return (dy1>= dy2)?DFB_OK:bblit_some?DFB_INCOMPLETE:DFB_UNSUPPORTED;
}

static CoreSurface *tempSrcSur= NULL,*tempDstSur = NULL;
static CardState newstate;
static pthread_mutex_t nstate_lock  = PTHREAD_MUTEX_INITIALIZER;

static bool stateinited = false;
#define MAX_HEIGHT_HW_SUPPORT   4096
#define MAX_WIDTH_HW_SUPPORT   4096


DFBResult dfb_gfxcard_stretchblit_inner( DFBRectangle *srect, DFBRectangle *drect,
                              CardState *state );


DFBResult dfb_gfxcard_stretchblit(  DFBRectangle *srect,
                                                                DFBRectangle *drect,
                                                                CardState *state )

{
    u8 u8StretchDownRatio;
    DFBResult ret;
//1. check the stretch down ratio is supported by the HW
    u8StretchDownRatio = dfb_config->stretchdown_patch_ratio; //current let it be 2, power(1)
    //todo!!! query it from utopia...

    // line stretchblit patch
    if ( dfb_config->sw_render == SWRF_NONE && dfb_config->line_stretchblit_patch 
		&& ( (srect->w > srect->h) && (srect->h == 1) ) )
    {
        CoreSurface *tmpSurface = NULL;
	 CardState tmpState;
	 DFBRectangle tmpRect = {0};
	 
/*printf("[sheng] dfb_gfxcard_stretchblit,  srect (%d, %d, %dx%d) , drect (%d, %d, %dx%d)\n",
	srect->x, srect->y, srect->w, srect->h, drect->x, drect->y, drect->w, drect->h);*/
	 // create temp surface height = 2,	
	 dfb_surface_create_simple( card->core, srect->w, 2,
               state->destination->config.format, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
               &tmpSurface);

	 dfb_state_init(&tmpState, state->core);
	 tmpState.src_blend = DSBF_ONE;
	 tmpState.dst_blend = DSBF_ZERO;
	 tmpState.modified  = state->modified;
	 tmpState.source = state->source;
	 tmpState.destination = tmpSurface;
	 tmpState.clip.x1 = 0;
	 tmpState.clip.y1 = 0;
	 tmpState.clip.x2 = tmpSurface->config.size.w - 1;
	 tmpState.clip.y2 = tmpSurface->config.size.h - 1;
/*printf("[sheng] dfb_gfxcard_stretchblit, srect->w=%d, srect->h=%d, state->modified=%d, clip(%d - %d, %d - %d) \n",
	, srect->w, srect->h, state->modified, tmpState.clip.x1, tmpState.clip.y1, tmpState.clip.x2, tmpState.clip.y2);*/

	 // fill temp surface
	 dfb_gfxcard_blit(srect, 0, 0, &tmpState);
	 dfb_gfxcard_blit(srect, 0, 1, &tmpState);
	 
	 // change original state source to temp surface.
	 //state->source = tmpSurface;
	 dfb_state_set_source(state, tmpSurface);

        // set temp surface rect x, y to 0.
        tmpRect.x = 0;
        tmpRect.y = 0;
        tmpRect.w = srect->w;
        tmpRect.h = srect->h;
	
	 dfb_gfxcard_stretchblit_inner(&tmpRect, drect, state);	 
	 dfb_surface_unref(tmpSurface);
	 tmpSurface = NULL;
	 
	 return DFB_OK;
    }
	
    //if config don't do patch   OR   doesn't need to do patch,
    //just go through the stretchblit function.
  
    if(!dfb_config->do_stretchdown_patch || (srect->w < ((drect->w<<u8StretchDownRatio) + 1)) && (srect->h < ((drect->h<<u8StretchDownRatio) + 1)))
    {//go straight to the HW stretchblit
        return dfb_gfxcard_stretchblit_inner(srect,drect,state);
    }
    else if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) {
          if (srect->w == drect->h && srect->h == drect->w) {
               return dfb_gfxcard_blit( srect, drect->x, drect->y, state );
          }
    }
    else if(state->blittingflags & DSBLIT_SRC_COLORKEY) // Go to SW blit when set source color key enable. 
    {
        DFBAccelerationMask      orign_accel_mask;

        orign_accel_mask = state->disabled;       
        state->disabled = DFXL_ALL;   // disable all drawing/blitting functions of HW.  
        
        ret = dfb_gfxcard_stretchblit_inner(srect,drect,state);

        state->disabled  = orign_accel_mask;  //recover the original setting. 
        
        return ret;
    }

//2.Patch
    //stretchblit to temp surface
    DFBRectangle tempRect = {0};
    bool thelast = false;
    u8 u8times = 0,hw;
    CoreSurface   *orign_source_surface = NULL;


    //!!todo, get the HW limitate from utopia
    if(MAX_HEIGHT_HW_SUPPORT < state->source->config.size.h || MAX_WIDTH_HW_SUPPORT < state->source->config.size.w)
    {
        printf("warning!!! [%d,%d] Beyond the HW limitation [%d,%d] \n",
        state->source->config.size.w,state->source->config.size.h,MAX_WIDTH_HW_SUPPORT,MAX_HEIGHT_HW_SUPPORT);
        return DFB_UNSUPPORTED;
    }

    if(!stateinited)
    {
        dfb_state_init( &newstate, NULL );
        newstate.src_blend      = DSBF_ONE;
        newstate.dst_blend      = DSBF_ZERO;
        stateinited = true;
    }

    pthread_mutex_lock( &nstate_lock );
    while(1)
    {
        if((srect->w < ((drect->w<<1) + 1)) && (srect->h < ((drect->h<<1) + 1)))
        {
            thelast = true;
        }
        memcpy(&tempRect,srect,sizeof(DFBRectangle));
        if(srect->w >= ((drect->w<<1) + 1))
        {
            tempRect.w = (srect->w + 1)>>1;
        }

        if(srect->h >= ((drect->h<<1) + 1))
        {
            tempRect.h = (srect->h + 1)>>1;
        }
        tempRect.x = 0;
        tempRect.y = 0;


        if(tempSrcSur == NULL)
        {
            if(dfb_config->static_stretchdown_buf)
            {
                dfb_surface_create_simple( card->core, MAX_HEIGHT_HW_SUPPORT/2,
                      MAX_WIDTH_HW_SUPPORT/2,
                      state->destination->config.format, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
                      &tempSrcSur);
            }
            else
            {
                dfb_surface_create_simple( card->core, tempRect.w,tempRect.h,
               state->destination->config.format, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
               &tempSrcSur);
            }
        }

        if(tempDstSur == NULL)
        {
            if(u8times > 0)
            {
                if(dfb_config->static_stretchdown_buf)
                {
                    dfb_surface_create_simple(  card->core, MAX_HEIGHT_HW_SUPPORT/4,
                          MAX_WIDTH_HW_SUPPORT/4,
                          state->destination->config.format, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
                          &tempDstSur);
                }
                else
                {               
                    dfb_surface_create_simple(  card->core,  tempRect.w,tempRect.h,
                   state->destination->config.format, DSCAPS_VIDEOONLY, CSTF_INTERNAL, 0, NULL,
                   &tempDstSur);
                }
            }
        }

        newstate.modified     |= SMF_SOURCE | SMF_DESTINATION;

        if(u8times == 0)
        {//the first time, orginal src->tempsrc

            newstate.source = state->source;
            newstate.destination = tempSrcSur;
            
        }
        else
        {//
            if((u8times & 0x1 )== 0)  //u8times % 2 == 0
            {   //tempsrc->tempdest
                newstate.source = tempDstSur;
                newstate.destination = tempSrcSur;
            }
            else
            {//tempdest->tempsrc

                newstate.source = tempSrcSur;
                newstate.destination = tempDstSur;
            }
        }

        if(thelast)
        {
            memcpy(&tempRect,drect,sizeof(DFBRectangle));

            state->modified     |= SMF_CLIP;
            orign_source_surface =  state->source ;
            state->source = newstate.source ;

            ret = dfb_gfxcard_stretchblit_inner(srect,&tempRect,state);
               
           
        }
        else
        {
            newstate.modified     |= SMF_CLIP;
            newstate.clip.x1       = 0;
            newstate.clip.y1       = 0;
            newstate.clip.x2       = newstate.destination->config.size.w - 1;
            newstate.clip.y2       = newstate.destination->config.size.h - 1;  

            ret = dfb_gfxcard_stretchblit_inner(srect, &tempRect,&newstate);
           // printf("dfb_gfxcard_stretchblit2 , ret = %d \n",ret);

        }

        //printf("u8times=%d,StretchBlit ret = %d, thelast = %d, srect[%d,%d,%d,%d] , tempRect[%d,%d,%d,%d]\n",
        //u8times,ret,thelast,srect->x,srect->y,srect->w,srect->h, tempRect.x,tempRect.y,tempRect.w,tempRect.h);

        if(ret != DFB_OK)
            break;

        if(thelast)
        {
      
            ret = DFB_OK;
            break;
   
        }

        memcpy(srect,&tempRect,sizeof(DFBRectangle));

        u8times++;
    }

    dfb_state_stop_drawing( &newstate );

    if(!dfb_config->static_stretchdown_buf)
    {//not static buffer, release it after use.
        if(tempSrcSur)
        {        
            dfb_surface_unref( tempSrcSur );
            tempSrcSur = NULL;
        }

        if(tempDstSur)
        {
            dfb_surface_unref( tempDstSur );
            tempDstSur = NULL;
        }
    }

    state->modified |= SMF_SOURCE;
    state->source = orign_source_surface;
    
    pthread_mutex_unlock( &nstate_lock );
    
    return ret;
}


DFBResult dfb_gfxcard_stretchblit_inner( DFBRectangle *srect, DFBRectangle *drect,
                              CardState *state )
{
     bool hw = false;
     DFBResult result = DFB_OK;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( srect != NULL );
     D_ASSERT( drect != NULL );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d -> %d,%d - %dx%d, %p )\n",
                 __FUNCTION__, DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect), state );

     if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) {
          if (srect->w == drect->h && srect->h == drect->w) {
               return dfb_gfxcard_blit( srect, drect->x, drect->y, state );
          }
     }
     else {
          if (srect->w == drect->w && srect->h == drect->h) {
               return dfb_gfxcard_blit( srect, drect->x, drect->y, state );
          }
     }

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!(state->render_options & DSRO_MATRIX) &&
         !dfb_clip_blit_precheck( &state->clip, drect->w, drect->h,
                                  drect->x, drect->y ))
     {
          dfb_state_unlock( state );
          return DFB_OK;
     }

     if (dfb_gfxcard_state_check( state, DFXL_STRETCHBLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_STRETCHBLIT ))
     {
          if ((!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_STRETCHBLIT ))||dfb_sw_clip_needed(srect,drect))
               dfb_clip_stretchblit( &state->clip, srect, drect );

          hw = card->funcs.StretchBlit( card->driver_data, card->device_data, srect, drect );

          dfb_gfxcard_state_release( state );
     }

     if (!hw) {
          if (state->render_options & DSRO_MATRIX) {
               int x1, y1, x2, y2;

               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0) {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return DFB_UNSUPPORTED;
               }

               x1 = drect->x;    y1 = drect->y;
               x2 = x1+drect->w; y2 = y1+drect->h;
               DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
               DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);
               drect->x = x1;    drect->y = y1;
               drect->w = x2-x1; drect->h = y2-y1;

               if (!dfb_clip_blit_precheck( &state->clip,
                                            drect->w, drect->h, drect->x, drect->y )) {
                    dfb_state_unlock( state );
                    return DFB_OK;
               }
          }

          if (gAcquire( state, DFXL_STRETCHBLIT )) {
               /* Clipping is performed in the following function. */
               gStretchBlit( state, srect, drect );
               gRelease( state );
          }
          else
                 result =  DFB_UNSUPPORTED;
     }

     dfb_state_unlock( state );
     return result;
}

DFBResult dfb_gfxcard_stretchblitEx( DFBRectangle *srect, DFBRectangle *drect,
                              CardState *state, const DFBGFX_ScaleInfo *scale_info)
{
     bool hw = false;
     DFBResult result = DFB_OK;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( srect != NULL );
     D_ASSERT( drect != NULL );

     D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d -> %d,%d - %dx%d, %p )\n",
                 __FUNCTION__, DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect), state );

     if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) {
          if (srect->w == drect->h && srect->h == drect->w) {
               return dfb_gfxcard_blit( srect, drect->x, drect->y, state );
          }
     }
     else {
          if (srect->w == drect->w && srect->h == drect->h) {
               return dfb_gfxcard_blit( srect, drect->x, drect->y, state );
          }
     }

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if (!(state->render_options & DSRO_MATRIX) &&
         !dfb_clip_blit_precheck( &state->clip, drect->w, drect->h,
                                  drect->x, drect->y ))
     {
          dfb_state_unlock( state );
          return DFB_OK;
     }

     if (dfb_gfxcard_state_check( state, DFXL_STRETCHBLIT ) &&
         dfb_gfxcard_state_acquire( state, DFXL_STRETCHBLIT ))
     {
          if ((!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) &&
              !D_FLAGS_IS_SET( card->caps.clip, DFXL_STRETCHBLIT ))||dfb_sw_clip_needed(srect,drect))
               dfb_clip_stretchblit( &state->clip, srect, drect );

          hw = card->funcs.StretchBlitEx( card->driver_data, card->device_data, srect, drect, scale_info);

          dfb_gfxcard_state_release( state );
     }

     if (!hw) {
          if (state->render_options & DSRO_MATRIX) {
               int x1, y1, x2, y2;

               if (state->matrix[0] < 0  || state->matrix[1] != 0 ||
                   state->matrix[3] != 0 || state->matrix[4] < 0  ||
                   state->matrix[6] != 0 || state->matrix[7] != 0) {
                    D_WARN( "rotation not yet implemented" );
                    dfb_state_unlock( state );
                    return DFB_UNSUPPORTED;
               }

               x1 = drect->x;    y1 = drect->y;
               x2 = x1+drect->w; y2 = y1+drect->h;
               DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix);
               DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix);
               drect->x = x1;    drect->y = y1;
               drect->w = x2-x1; drect->h = y2-y1;

               if (!dfb_clip_blit_precheck( &state->clip,
                                            drect->w, drect->h, drect->x, drect->y )) {
                    dfb_state_unlock( state );
                    return DFB_OK;
               }
          }

          if (gAcquire( state, DFXL_STRETCHBLIT )) {
               /* Clipping is performed in the following function. */
               gStretchBlit( state, srect, drect );
               gRelease( state );
          }
          else
              result = DFB_UNSUPPORTED;
     }

     dfb_state_unlock( state );
     return result;
}




DFBResult dfb_gfxcard_texture_triangles( DFBVertex *vertices, int num,
                                    DFBTriangleFormation formation,
                                    CardState *state )
{
     bool hw = false;
     DFBResult result = DFB_OK;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %s, %p )\n", __FUNCTION__, vertices, num,
                 (formation == DTTF_LIST)  ? "LIST"  :
                 (formation == DTTF_STRIP) ? "STRIP" :
                 (formation == DTTF_FAN)   ? "FAN"   : "unknown formation", state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_ASSERT( vertices != NULL );
     D_ASSERT( num >= 3 );
     D_MAGIC_ASSERT( state, CardState );

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     if ((D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_TEXTRIANGLES )) &&
         dfb_gfxcard_state_check( state, DFXL_TEXTRIANGLES ) &&
         dfb_gfxcard_state_acquire( state, DFXL_TEXTRIANGLES ))
     {
          hw = card->funcs.TextureTriangles( card->driver_data,
                                             card->device_data,
                                             vertices, num, formation );

          dfb_gfxcard_state_release( state );
     }

     if (!hw) {
          if (gAcquire( state, DFXL_TEXTRIANGLES )) {
               //dfb_clip_stretchblit( &state->clip, srect, drect );
               //gStretchBlit( state, srect, drect );
               gRelease( state );
          }
          else
                result = DFB_UNSUPPORTED;
     }

     dfb_state_unlock( state );
     return result;
}

DFBResult
dfb_gfxcard_drawstring( const u8 *text, int bytes,
                        DFBTextEncodingID encoding, int x, int y,
                        CoreFont *font, unsigned int layers, CardState *state, DFBMatrix *pmatrix, 
                        unsigned long attrFlag, DFBSurfaceTextFlags flags)
{
     unsigned int             prev = 0;
     unsigned int             indices[bytes];
     memset( indices, 0, bytes*sizeof(unsigned int));//Fix converity END
     int                      i, l, num = 0;//Fix converity END
     int                      kern_x;
     int                      kern_y;
     CoreSurface             *surface;
     DFBSurfaceBlittingFlags  orig_flags;
     DFBSurfaceBlendFunction  orig_srcblend;
     DFBSurfaceBlendFunction  orig_dstblend;
     DFBPoint                 points[50];
     DFBRectangle             rects[50];
     int                      num_blits = 0;
     int                      ox = x;
     int                      oy = y;
     int                      result_msk = 0;
     bool                     set_blend = true;
     DFBResult          ret;

     if (encoding == DTEID_UTF8)
          D_DEBUG_AT( Core_GraphicsOps, "%s( '%s' [%d], %d,%d, %p, %p )\n",
                      __FUNCTION__, text, bytes, x, y, font, state );
     else
          D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %d, %d,%d, %p, %p )\n",
                      __FUNCTION__, text, bytes, encoding, x, y, font, state );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( text != NULL );
     D_ASSERT( bytes > 0 );
     D_ASSERT( font != NULL );

     surface = state->destination;
     D_MAGIC_ASSERT( surface, CoreSurface );
     set_blend = !(flags & DSTF_BLEND_FUNCS);

     /* simple prechecks */
     if (!(state->render_options & DSRO_MATRIX) &&
         (x > state->clip.x2 || y > state->clip.y2 ||
          y + font->ascender - font->descender <= state->clip.y1)) {
          return DFB_OK;
     }

     dfb_font_lock( font );

     /* Decode string to character indices. */
     ret = dfb_font_decode_text( font, encoding, text, bytes, indices, &num );
     if(ret != DFB_OK)
     {
        printf("dfb_font_decode_text failed with ret = %d \n",ret);
        return DFB_UNSUPPORTED;
     }

     orig_flags    = state->blittingflags;
     orig_srcblend = state->src_blend;
     orig_dstblend = state->dst_blend;

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          DFBSurfaceBlittingFlags flags = font->blittingflags;

          /* additional blending? */
          if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff))
               flags |= DSBLIT_BLEND_COLORALPHA;

          if (state->drawingflags & DSDRAW_DST_COLORKEY)
               flags |= DSBLIT_DST_COLORKEY;

          if (state->drawingflags & DSDRAW_XOR)
               flags |= DSBLIT_XOR;

          if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
               /* Porter/Duff SRC_OVER composition */
               if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED))
                   ||
                   (font->surface_caps & DSCAPS_PREMULTIPLIED))
               {
                    if (font->surface_caps & DSCAPS_PREMULTIPLIED) {
                         if (flags & DSBLIT_BLEND_COLORALPHA)
                              flags |= DSBLIT_SRC_PREMULTCOLOR;
                    }
                    else
                         flags |= DSBLIT_SRC_PREMULTIPLY;
                    if (set_blend)
                       dfb_state_set_src_blend( state, DSBF_ONE );
               }
               else if (set_blend)
                   dfb_state_set_src_blend( state,DSBF_SRCALPHA );
               
               if (set_blend)
                   dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA);
          }

          dfb_state_set_blitting_flags( state, flags );
     }

     for (l=layers-1; l>=0; l--) {
          x = ox;
          y = oy;

          if (layers > 1)
               dfb_state_set_color( state, &state->colors[l] );


          /* blit glyphs */
          for (i=0; i<num; i++) {
               DFBResult      ret;
               CoreGlyphData *glyph;
               unsigned int   current = indices[i];

               ret = dfb_font_get_glyph_data( font, current, l, &glyph, pmatrix, attrFlag);
               if (ret) {
                    D_DEBUG_AT( Core_GraphicsOps, "  -> dfb_font_get_glyph_data() failed! [%s]\n", DirectFBErrorString( ret ) );
                    prev = current;
                    continue;
               }

               if (prev && font->GetKerning && font->GetKerning( font, prev, current, &kern_x, &kern_y) == DFB_OK) {
                    x += kern_x;
                    y += kern_y;
               }

               if (glyph->width) {
                    if (glyph->surface != state->source || num_blits == D_ARRAY_SIZE(rects)) {
                         if (num_blits) {

                              if(DFB_OK == dfb_gfxcard_batchblit( rects, points, num_blits, state ))
                                result_msk |= 1;
                              else
                                result_msk |= 2;

                              num_blits = 0;
                         }

                         if (glyph->surface != state->source)
                              dfb_state_set_source( state, glyph->surface );
                    }


					points[num_blits] = (DFBPoint){ x + glyph->left, y + glyph->top };

                    rects[num_blits]  = (DFBRectangle){ glyph->start, 0, glyph->width, glyph->height };

					/*
					printf("\nflyph->left:%d,glyph->top:%d\n",glyph->left,glyph->top);
					printf("\nthe glyph->surface %x\n",glyph->surface);
					printf("\nnum_blits:%d",num_blits);
					printf("\npointx x:%d y:%d\n",points[num_blits].x,points[num_blits].y);
					printf("\nrects x:%d y:%d w:%d h:%d\n",rects[num_blits].x,rects[num_blits].y,rects[num_blits].w,rects[num_blits].h);
					*/
                    num_blits++;
               }

               x   += glyph->advance;
               prev = current;
          }

		  if (num_blits) {

          if(DFB_OK == dfb_gfxcard_batchblit( rects, points, num_blits, state ))
               result_msk |= 1;
          else
               result_msk |= 2;
          num_blits = 0;
     }



     }



     dfb_font_unlock( font );


     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          dfb_state_set_blitting_flags( state, orig_flags );
          dfb_state_set_src_blend( state, orig_srcblend );
          dfb_state_set_dst_blend( state, orig_dstblend );
     }
     return (result_msk<=1)?DFB_OK: (result_msk==2)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult dfb_gfxcard_drawglyph( CoreGlyphData **glyph, int x, int y,
                            CoreFont *font, unsigned int layers, CardState *state )
{
     int                      l;
     CoreSurface             *surface;
     DFBSurfaceBlittingFlags  orig_flags;
     DFBSurfaceBlendFunction  orig_srcblend;
     DFBSurfaceBlendFunction  orig_dstblend;
     int                      result_msk = 0;

     D_DEBUG_AT( Core_GraphicsOps, "%s( %u, %d,%d, %p, %p %p )\n",
                 __FUNCTION__, layers, x, y, font, state, glyph );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( font != NULL );

     surface = state->destination;
     D_MAGIC_ASSERT( surface, CoreSurface );

     orig_flags    = state->blittingflags;
     orig_srcblend = state->src_blend;
     orig_dstblend = state->dst_blend;

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          DFBSurfaceBlittingFlags flags = font->blittingflags;

          /* additional blending? */
          if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff))
               flags |= DSBLIT_BLEND_COLORALPHA;

          if (state->drawingflags & DSDRAW_DST_COLORKEY)
               flags |= DSBLIT_DST_COLORKEY;

          if (state->drawingflags & DSDRAW_XOR)
               flags |= DSBLIT_XOR;

          if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
               /* Porter/Duff SRC_OVER composition */
               if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED))
                   ||
                   (font->surface_caps & DSCAPS_PREMULTIPLIED))
               {
                    if (font->surface_caps & DSCAPS_PREMULTIPLIED) {
                         if (flags & DSBLIT_BLEND_COLORALPHA)
                              flags |= DSBLIT_SRC_PREMULTCOLOR;
                    }
                    else
                         flags |= DSBLIT_SRC_PREMULTIPLY;

                    dfb_state_set_src_blend( state, DSBF_ONE );
               }
               else
                    dfb_state_set_src_blend( state, DSBF_SRCALPHA );

               dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA );
          }

          dfb_state_set_blitting_flags( state, flags );
     }

     for (l=layers-1; l>=0; l--) {
          if (layers > 1)
               dfb_state_set_color( state, &state->colors[l] );

          /* blit glyph */
          if (glyph[l]->width) {
               DFBRectangle rect = { glyph[l]->start, 0, glyph[l]->width, glyph[l]->height };

               dfb_state_set_source( state, glyph[l]->surface );

               if(DFB_OK == dfb_gfxcard_blit( &rect, x + glyph[l]->left, y + glyph[l]->top, state ))
                   result_msk |= 1;
               else
                   result_msk |= 2;
          }
     }

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          dfb_state_set_blitting_flags( state, orig_flags );
          dfb_state_set_src_blend( state, orig_srcblend );
          dfb_state_set_dst_blend( state, orig_dstblend );
     }
     return (result_msk<=1)?DFB_OK: (result_msk==2)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

DFBResult dfb_gfxcard_drawglyphs              ( unsigned int          *index,
                                          int                  *x,
                                          int                  *y,
                                          CoreFont             *font,
                                          unsigned int         layers,
                                          CardState            *state,
                                          unsigned int         num )
{
     DFBResult      ret;
     DFBRectangle     rect;
     DFBMatrix        tilt_matrix = { 0x10000L, 0, 0, 0x10000L };
     unsigned long    attrFlag = 0x0;
     int              i;
     int              blit = 0;
     CoreGlyphData    *glyph[DFB_FONT_MAX_LAYERS];
     int              hw_clipping = D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) ||
                                      D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT );
     int              l;
     CoreSurface             *surface;
     DFBSurfaceBlittingFlags  orig_flags;
     DFBSurfaceBlendFunction  orig_srcblend;
     DFBSurfaceBlendFunction  orig_dstblend;
     int                      result_msk = 0;


     D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p, %p, %p, %p, %d )\n",
                 __FUNCTION__, index, x, y, font, state, num );

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( font != NULL );

     surface = state->destination;
     D_MAGIC_ASSERT( surface, CoreSurface );

     orig_flags    = state->blittingflags;
     orig_srcblend = state->src_blend;
     orig_dstblend = state->dst_blend;

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          DFBSurfaceBlittingFlags flags = font->blittingflags;

          /* additional blending? */
          if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff))
               flags |= DSBLIT_BLEND_COLORALPHA;

          if (state->drawingflags & DSDRAW_DST_COLORKEY)
               flags |= DSBLIT_DST_COLORKEY;

          if (state->drawingflags & DSDRAW_XOR)
               flags |= DSBLIT_XOR;

          if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
               /* Porter/Duff SRC_OVER composition */
               if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED))
                   ||
                   (font->surface_caps & DSCAPS_PREMULTIPLIED))
               {
                    if (font->surface_caps & DSCAPS_PREMULTIPLIED) {
                         if (flags & DSBLIT_BLEND_COLORALPHA)
                              flags |= DSBLIT_SRC_PREMULTCOLOR;
                    }
                    else
                         flags |= DSBLIT_SRC_PREMULTIPLY;

                    dfb_state_set_src_blend( state, DSBF_ONE );
               }
               else
                    dfb_state_set_src_blend( state, DSBF_SRCALPHA );

               dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA );
          }

          dfb_state_set_blitting_flags( state, flags );
     }

     /* The state is locked during graphics operations. */
     dfb_state_lock( state );

     /* Signal beginning of sequence of operations if not already done. */
     dfb_state_start_drawing( state, card );

     dfb_font_lock( font );

     /* blit glyphs */
     for (i=0; i<num; i++) {
         for (l=layers-1; l>=0; l--) {
              if (layers > 1)
                   dfb_state_set_color( state, &state->colors[l] );

              ret = dfb_font_get_glyph_data (font, index[i], l, &glyph[l], &tilt_matrix, attrFlag );
              if (ret)
                   D_DEBUG_AT( Core_Graphics, "  -> dfb_font_get_glyph_data() failed! [%s]\n",
                               DirectFBErrorString( ret ) );

              if (ret || !glyph[l]->width ||!index[i] )
                   continue;

              x[i] += glyph[l]->left;
              y[i] += glyph[l]->top;

              if (! dfb_clip_blit_precheck( &(state->clip), glyph[l]->width, glyph[l]->height, x[i], y[i] ))
                   continue;

              if (state->source != glyph[l]->surface || !blit) {
                   switch (blit) {
                        case 1:
                             dfb_gfxcard_state_release( state );
                             break;
                        case 2:
                             gRelease( state );
                             break;
                        default:
                             break;
                   }

                   dfb_state_set_source( state, glyph[l]->surface );

                   if (dfb_gfxcard_state_check( state, DFXL_BLIT ) &&
                       dfb_gfxcard_state_acquire( state, DFXL_BLIT ))
                        blit = 1, result_msk|=1;
                   else if (gAcquire( state, DFXL_BLIT ))
                        blit = 2, result_msk |=1;
                   else
                        blit = 0, result_msk |=2;
              }

              rect.x = glyph[l]->start;
              rect.y = 0;
              rect.w = glyph[l]->width;
              rect.h = glyph[l]->height;

              switch (blit) {
                   case 1:
                        if (!hw_clipping)
                             dfb_clip_blit( &(state->clip), &rect, &x[i], &y[i] );

                        card->funcs.Blit( card->driver_data, card->device_data, &rect, x[i], y[i] );
                        break;
                   case 2:
                        dfb_clip_blit( &(state->clip), &rect, &(x[i]), &(y[i]) );
                        gBlit( state, &rect, x[i], y[i] );
                        break;
                   default:
                        break;
              }
         }
     }

     switch (blit) {
          case 1:
               dfb_gfxcard_state_release( state );
               break;
          case 2:
               gRelease( state );
               break;
          default:
               break;
     }

     dfb_font_unlock( font );

     dfb_state_unlock( state );

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          dfb_state_set_blitting_flags( state, orig_flags );
          dfb_state_set_src_blend( state, orig_srcblend );
          dfb_state_set_dst_blend( state, orig_dstblend );
     }
     return (result_msk<=1)?DFB_OK: (result_msk==2)?DFB_UNSUPPORTED:DFB_INCOMPLETE;
}

bool dfb_gfxcard_drawstring_check_state( CoreFont *font, CardState *state )
{
     int                      i;
     bool                     result;
     CoreSurface             *surface;
     DFBSurfaceBlittingFlags  orig_flags;
     DFBSurfaceBlendFunction  orig_srcblend;
     DFBSurfaceBlendFunction  orig_dstblend;
     CoreGlyphData           *data = NULL;
     DFBMatrix               tilt_matrix;
     unsigned long           attrFlag = 0x0;

     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );
     D_MAGIC_ASSERT( state, CardState );
     D_ASSERT( font != NULL );

     D_DEBUG_AT( Core_GfxState, "%s( %p, %p )\n", __FUNCTION__, font, state );

     tilt_matrix.xx = 0x10000L;
     tilt_matrix.xy = 0;
     tilt_matrix.yx = 0;
     tilt_matrix.yy = 0x10000L;

     surface = state->destination;
     D_MAGIC_ASSERT( surface, CoreSurface );

     dfb_font_lock( font );

     for (i=0; i<128; i++) {
          if (dfb_font_get_glyph_data (font, i, 0, &data, &tilt_matrix, attrFlag) == DFB_OK)
               break;
     }

     if (!data) {
          D_DEBUG_AT( Core_GfxState, "  -> No font data!\n" );
          dfb_font_unlock( font );
          return false;
     }

     orig_flags    = state->blittingflags;
     orig_srcblend = state->src_blend;
     orig_dstblend = state->dst_blend;

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          DFBSurfaceBlittingFlags flags = font->blittingflags;

          /* additional blending? */
          if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff))
               flags |= DSBLIT_BLEND_COLORALPHA;

          if (state->drawingflags & DSDRAW_DST_COLORKEY)
               flags |= DSBLIT_DST_COLORKEY;

          if (state->drawingflags & DSDRAW_XOR)
               flags |= DSBLIT_XOR;

          if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) {
               /* Porter/Duff SRC_OVER composition */
               if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED))
                   ||
                   (font->surface_caps & DSCAPS_PREMULTIPLIED))
               {
                    if (font->surface_caps & DSCAPS_PREMULTIPLIED) {
                         if (flags & DSBLIT_BLEND_COLORALPHA)
                              flags |= DSBLIT_SRC_PREMULTCOLOR;
                    }
                    else
                         flags |= DSBLIT_SRC_PREMULTIPLY;

                    dfb_state_set_src_blend( state, DSBF_ONE );
               }
               else
                    dfb_state_set_src_blend( state, DSBF_SRCALPHA );

               dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA );
          }

          dfb_state_set_blitting_flags( state, flags );
     }

     /* set the source */
     dfb_state_set_source( state, data->surface );

     dfb_state_lock( state );

     /* check for blitting and report */
     result = dfb_gfxcard_state_check( state, DFXL_BLIT );

     dfb_state_unlock( state );

     dfb_font_unlock( font );

     if (orig_flags != DSBLIT_INDEX_TRANSLATION) {
          dfb_state_set_blitting_flags( state, orig_flags );
          dfb_state_set_src_blend( state, orig_srcblend );
          dfb_state_set_dst_blend( state, orig_dstblend );
     }

     return result;
}

DFBResult dfb_gfxcard_sync( void )
{
     DFBResult ret;

     D_ASSUME( card != NULL );

     if (!card)
          return DFB_OK;

     ret = dfb_gfxcard_lock( GDLF_SYNC );
     if (ret)
          return ret;

     dfb_gfxcard_unlock();

     return DFB_OK;
}

void dfb_gfxcard_invalidate_state( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     card->shared->state = NULL;
}

DFBResult dfb_gfxcard_wait_serial( const CoreGraphicsSerial *serial )
{
     DFBResult ret;

     D_ASSERT( serial != NULL );
     D_ASSUME( card != NULL );

     if (!card)
          return DFB_OK;

     D_ASSERT( card->shared != NULL );

     ret = dfb_gfxcard_lock( GDLF_NONE );
     if (ret)
          return ret;

     if (card->funcs.WaitSerial)
          ret = card->funcs.WaitSerial( card->driver_data, card->device_data, serial );
     else if (card->funcs.EngineSync)
          ret = card->funcs.EngineSync( card->driver_data, card->device_data );

     if (ret) {
          if (card->funcs.EngineReset)
               card->funcs.EngineReset( card->driver_data, card->device_data );

          card->shared->state = NULL;
     }

     dfb_gfxcard_unlock();

     return ret;
}

DFBResult dfb_gfxcard_sync_surface(CardState  *state, DFBSurfaceSyncFlags flags)
{
    DFBResult ret;


     D_ASSUME( card != NULL );

     if (!card)
          return DFB_OK;
     D_ASSERT( card->shared != NULL );

     ret = dfb_gfxcard_lock( GDLF_NONE );

     if(flags & DSUF_SYNC_ROUGH)
              ret = dfb_gfxcard_wait_serial((const CoreGraphicsSerial*)&state->serial);
     else
              ret = dfb_surface_sync_allocations(state->destination, flags);

     dfb_gfxcard_unlock();

     return ret;
}
void dfb_gfxcard_flush_texture_cache( void )
{
     D_ASSUME( card != NULL );

     if (card && card->funcs.FlushTextureCache)
          card->funcs.FlushTextureCache( card->driver_data, card->device_data );
}

void dfb_gfxcard_flush_read_cache( void )
{
     D_ASSUME( card != NULL );

     if (card && card->funcs.FlushReadCache)
          card->funcs.FlushReadCache( card->driver_data, card->device_data );
}

void dfb_gfxcard_after_set_var( void )
{
     D_ASSUME( card != NULL );

     if (card && card->funcs.AfterSetVar)
          card->funcs.AfterSetVar( card->driver_data, card->device_data );
}

void dfb_gfxcard_surface_enter( CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags )
{
     D_ASSUME( card != NULL );

     if (card && card->funcs.SurfaceEnter)
          card->funcs.SurfaceEnter( card->driver_data, card->device_data, buffer, flags );
}

void dfb_gfxcard_surface_leave( CoreSurfaceBuffer *buffer )
{
     D_ASSUME( card != NULL );

     if (card && card->funcs.SurfaceLeave)
          card->funcs.SurfaceLeave( card->driver_data, card->device_data, buffer );
}

DFBResult
dfb_gfxcard_adjust_heap_offset( int offset )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

//FIXME_SMAN     return dfb_surfacemanager_adjust_heap_offset( card->shared->surface_manager, offset );
     return DFB_OK;
}

void
dfb_gfxcard_get_capabilities( CardCapabilities *ret_caps )
{
     D_ASSERT( card != NULL );

     D_ASSERT( ret_caps != NULL );

     *ret_caps = card->caps;
}

void
dfb_gfxcard_get_device_info( GraphicsDeviceInfo *ret_info )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     D_ASSERT( ret_info != NULL );

     *ret_info = card->shared->device_info;
}

void
dfb_gfxcard_get_driver_info( GraphicsDriverInfo *ret_info )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     D_ASSERT( ret_info != NULL );

     *ret_info = card->shared->driver_info;
}


int
dfb_gfxcard_reserve_memory( CoreGraphicsDevice *device, unsigned int size )
{
     DFBGraphicsCoreShared *shared;

     D_ASSERT( device != NULL );
     D_ASSERT( device->shared != NULL );

     shared = device->shared;

     if (shared->device_info.limits.surface_byteoffset_alignment) {
          size += shared->device_info.limits.surface_byteoffset_alignment - 1;
          size -= (size % shared->device_info.limits.surface_byteoffset_alignment);
     }
     else
          D_WARN( "no alignment specified yet?" );

     if (shared->videoram_length < size) {
          D_WARN( "not enough video memory (%u < %u)", shared->videoram_length, size );
          return -1;
     }

     shared->videoram_length -= size;

     return shared->videoram_length;
}

int
dfb_gfxcard_reserve_auxmemory( CoreGraphicsDevice *device, unsigned int size )
{
     DFBGraphicsCoreShared *shared;
     int                    offset;

     D_ASSERT( device != NULL );
     D_ASSERT( device->shared != NULL );

     shared = device->shared;

     /* Reserve memory at the beginning of the aperture
      * to prevent overflows on DMA buffers. */

     offset = shared->auxram_offset;

     if (shared->auxram_length < (offset + size))
          return -1;

     shared->auxram_offset += size;

     return offset;
}

unsigned int
dfb_gfxcard_memory_length( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     return card->shared->videoram_length;
}

unsigned int
dfb_gfxcard_auxmemory_length( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     return card->shared->auxram_length;
}

volatile void *
dfb_gfxcard_map_mmio( CoreGraphicsDevice *device,
                      unsigned int        offset,
                      int                 length )
{
     return dfb_system_map_mmio( offset, length );
}

void
dfb_gfxcard_unmap_mmio( CoreGraphicsDevice *device,
                        volatile void      *addr,
                        int                 length )
{
     dfb_system_unmap_mmio( addr, length );
}

int
dfb_gfxcard_get_accelerator( CoreGraphicsDevice *device )
{
     return dfb_system_get_accelerator();
}

void
dfb_gfxcard_get_limits( CoreGraphicsDevice *device,
                        CardLimitations    *ret_limits )
{
     D_ASSERT( device != NULL );
     D_ASSERT( ret_limits != NULL );

     if (!device)
          device = card;

     *ret_limits = device->limits;
}

void
dfb_gfxcard_calc_buffer_size( CoreGraphicsDevice *device,
                              CoreSurfaceBuffer  *buffer,
                              int                *ret_pitch,
                              int                *ret_length )
{
     int          pitch;
     int          length;
     CoreSurface *surface;
     int          height_alignment=0;


     D_ASSERT( device != NULL );
     D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer );

     surface = buffer->surface;
     D_MAGIC_ASSERT( surface, CoreSurface );

     /* calculate the required length depending on limitations */
     pitch = MAX( surface->config.size.w, surface->config.min_size.w );

     if (pitch < device->limits.surface_max_power_of_two_pixelpitch &&
         surface->config.size.h < device->limits.surface_max_power_of_two_height)
          pitch = 1 << direct_log2( pitch );

     if (device->limits.surface_pixelpitch_alignment > 1) {
          pitch += device->limits.surface_pixelpitch_alignment - 1;
          pitch -= pitch % device->limits.surface_pixelpitch_alignment;
     }

     pitch = DFB_BYTES_PER_LINE( buffer->format, pitch );

     if (pitch < device->limits.surface_max_power_of_two_bytepitch &&
         surface->config.size.h < device->limits.surface_max_power_of_two_height)
          pitch = 1 << direct_log2( pitch );

     if (device->limits.surface_bytepitch_alignment > 1) {
          pitch += device->limits.surface_bytepitch_alignment - 1;
          pitch -= pitch % device->limits.surface_bytepitch_alignment;
     }

     if(dfb_config->mst_layer_bTiled[0]||dfb_config->mst_layer_bTiled[1]||
        dfb_config->mst_layer_bTiled[2]|| dfb_config->mst_layer_bTiled[3])
     {
        height_alignment = MAX( surface->config.size.h, surface->config.min_size.h );
        height_alignment += device->limits.surface_hegiht_alignment - 1;
        height_alignment -= height_alignment % device->limits.surface_hegiht_alignment;

     }
     else
     {
        height_alignment = MAX( surface->config.size.h, surface->config.min_size.h );
     }

     length = DFB_PLANE_MULTIPLY( buffer->format,
                                  height_alignment * pitch );

     /* Add extra space for optimized routines which are now allowed to overrun, e.g. prefetching. */
     length += 16;

     if (device->limits.surface_byteoffset_alignment > 1) {
          length += device->limits.surface_byteoffset_alignment - 1;
          length -= length % device->limits.surface_byteoffset_alignment;
     }

     if (ret_pitch)
          *ret_pitch = pitch;

     if (ret_length)
          *ret_length = length;
}

unsigned long
dfb_gfxcard_memory_physical( CoreGraphicsDevice *device,
                             unsigned int        offset )
{
     return dfb_system_video_memory_physical( offset );
}

void *
dfb_gfxcard_memory_virtual( CoreGraphicsDevice *device,
                            unsigned int        offset )
{
     return dfb_system_video_memory_virtual( offset );
}

unsigned long
dfb_gfxcard_auxmemory_physical( CoreGraphicsDevice *device,
                                unsigned int        offset )
{
     return dfb_system_aux_memory_physical( offset );
}

void *
dfb_gfxcard_auxmemory_virtual( CoreGraphicsDevice *device,
                               unsigned int        offset )
{
     return dfb_system_aux_memory_virtual( offset );
}

void *
dfb_gfxcard_get_device_data( void )
{
     D_ASSERT( card != NULL );
     D_ASSERT( card->shared != NULL );

     return card->shared->device_data;
}

void *
dfb_gfxcard_get_driver_data( void )
{
     D_ASSERT( card != NULL );

     return card->driver_data;
}

CoreGraphicsDevice *
dfb_gfxcard_get_primary( void )
{
     return card;
}


/** internal **/

/*
 * loads/probes/unloads one driver module after another until a suitable
 * driver is found and returns its symlinked functions
 */
static void dfb_gfxcard_find_driver( CoreDFB *core )
{
     DirectLink          *link;
     FusionSHMPoolShared *pool = dfb_core_shmpool( core );

     direct_list_foreach (link, dfb_graphics_drivers.entries) {
          DirectModuleEntry *module = (DirectModuleEntry*) link;

          const GraphicsDriverFuncs *funcs = direct_module_ref( module );

          if (!funcs)
               continue;

          if (!card->module && funcs->Probe( card )) {
               funcs->GetDriverInfo( card, &card->shared->driver_info );

               card->module       = module;
               card->driver_funcs = funcs;

               card->shared->module_name = SHSTRDUP( pool, module->name );
          }
          else
               direct_module_unref( module );
     }
}

/*
 * loads the driver module used by the session
 */
static void dfb_gfxcard_load_driver( void )
{
     DirectLink *link;

     if (!card->shared->module_name)
          return;

     direct_list_foreach (link, dfb_graphics_drivers.entries) {
          DirectModuleEntry *module = (DirectModuleEntry*) link;

          const GraphicsDriverFuncs *funcs = direct_module_ref( module );

          if (!funcs)
               continue;

          if (!card->module &&
              !strcmp( module->name, card->shared->module_name ))
          {
               card->module       = module;
               card->driver_funcs = funcs;
          }
          else
               direct_module_unref( module );
     }
}

