Hi,

Since we do have multiple hardware units supporting image decoding (and to make use of multiple cores on dektop CPUs), I want to make it easy for application writers to use multiple image providers in parallel, so here is a suggestion to update the IDirectFBImageProvider API to support this kind of feature.

I have also attached my current implementation for the JPEG provider which is working nicely for me.

What do you people think?


Cheers,
Andre'
>From 39e32e65dd5f82cd49279246f92a0efcf52f3aa3 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Andr=C3=A9=20Draszik?= <andre.dras...@st.com>
Date: Mon, 20 Apr 2009 20:44:58 +0100
Subject: [PATCH] (backgounded image providers) this is the API
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit

API definition for backgrounded image providers

Signed-off-by: André Draszik <andre.dras...@st.com>
---
 include/directfb.h                 |   64 ++++++++++++++++++++++++++++++++++++
 src/media/idirectfbimageprovider.c |   19 +++++++++++
 2 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/include/directfb.h b/include/directfb.h
index 1f35997..0c81d5a 100644
--- a/include/directfb.h
+++ b/include/directfb.h
@@ -5635,6 +5635,19 @@ DEFINE_INTERFACE(   IDirectFBFont,
 )
 
 /*
+ * Flags for image providers.
+ */
+typedef enum {
+    DIPFLAGS_NONE,
+    DIPFLAGS_BACKGROUND_DECODE
+} DFBImageProviderFlags;
+
+typedef enum {
+    DIPSYNCFLAGS_SYNC, /* sync, i.e. wait for the image provider to finish */
+    DIPSYNCFLAGS_TRYSYNC /* figure out if image provider is finished or still 
busy */
+} DFBImageProviderSyncFlags;
+
+/*
  * Capabilities of an image.
  */
 typedef enum {
@@ -5705,6 +5718,37 @@ DEFINE_INTERFACE(   IDirectFBImageProvider,
      );
 
 
+   /** Set Flags **/
+
+     /*
+      * Set image provider flags.
+      *
+      * This allows one to switch an image provider's mode of
+      * operation, between default and background.
+      *
+      * In default (which is also the traditional) mode, a call to
+      * RenderTo() will block until the image provider has finished
+      * decoding the image. This is also the behaviour if this API
+      * is not used at all.
+      *
+      * In background mode, the image is being decoded in the background,
+      * i.e. the call to RenderTo() will return almost immediately. The
+      * application may do other useful processing while the image is being
+      * decoded. In most implementations, background decode will just use
+      * a worker thread.
+      *
+      * Not all image providers support background mode and will return
+      * DFB_UNSUPPORTED in that case.
+      *
+      * Calling SetFlags() after RenderTo() makes no sense and is
+      * unsupported.
+      *
+      */
+     DFBResult (*SetFlags) (
+          IDirectFBImageProvider *thiz,
+          DFBImageProviderFlags   flags
+     );
+
    /** Rendering **/
 
      /*
@@ -5731,6 +5775,10 @@ DEFINE_INTERFACE(   IDirectFBImageProvider,
       * Registers a callback for progressive image loading.
       *
       * The function is called each time a chunk of the image is decoded.
+      *
+      * In case of an image provider working in the background, the
+      * callback could be called in a different thread context! So you
+      * might have to take appropriate actions to handle this.
       */
      DFBResult (*SetRenderCallback) (
           IDirectFBImageProvider   *thiz,
@@ -5739,6 +5787,22 @@ DEFINE_INTERFACE(   IDirectFBImageProvider,
      );
 
 
+     /*
+      * For a background image provider, waits for it to finish
+      * decoding the image.
+      *
+      * For a default image provider, does nothing.
+      *
+      * This needs to be called for background image providers
+      * before accessing the destination surface (using either the
+      * software or the hardware), to make sure that the image has been
+      * completely decoded.
+      */
+     DFBResult (*Sync) (
+          IDirectFBImageProvider    *thiz,
+          DFBImageProviderSyncFlags  flags
+     );
+
    /** Encoding **/
 
      /*
diff --git a/src/media/idirectfbimageprovider.c 
b/src/media/idirectfbimageprovider.c
index 6b6d6d9..5c434f8 100644
--- a/src/media/idirectfbimageprovider.c
+++ b/src/media/idirectfbimageprovider.c
@@ -79,6 +79,16 @@ IDirectFBImageProvider_GetImageDescription( 
IDirectFBImageProvider *thiz,
 }
 
 static DFBResult
+IDirectFBImageProvider_SetFlags ( IDirectFBImageProvider *thiz,
+                                  DFBImageProviderFlags   flags )
+{
+     if (flags == DIPFLAGS_NONE)
+          return DFB_OK;
+
+     return DFB_UNIMPLEMENTED;
+}
+
+static DFBResult
 IDirectFBImageProvider_RenderTo( IDirectFBImageProvider *thiz,
                                  IDirectFBSurface       *destination,
                                  const DFBRectangle     *destination_rect )
@@ -95,6 +105,13 @@ IDirectFBImageProvider_SetRenderCallback( 
IDirectFBImageProvider *thiz,
 }
 
 static DFBResult
+IDirectFBImageProvider_Sync( IDirectFBImageProvider    *thiz,
+                             DFBImageProviderSyncFlags  flags )
+{
+     return DFB_UNIMPLEMENTED;
+}
+
+static DFBResult
 IDirectFBImageProvider_WriteBack( IDirectFBImageProvider *thiz,
                                   IDirectFBSurface       *surface,
                                   const DFBRectangle     *src_rect,
@@ -110,8 +127,10 @@ IDirectFBImageProvider_Construct( IDirectFBImageProvider 
*thiz )
      thiz->Release               = IDirectFBImageProvider_Release;
      thiz->GetSurfaceDescription = 
IDirectFBImageProvider_GetSurfaceDescription;
      thiz->GetImageDescription   = IDirectFBImageProvider_GetImageDescription;
+     thiz->SetFlags              = IDirectFBImageProvider_SetFlags;
      thiz->RenderTo              = IDirectFBImageProvider_RenderTo;
      thiz->SetRenderCallback     = IDirectFBImageProvider_SetRenderCallback;
+     thiz->Sync                  = IDirectFBImageProvider_Sync;
      thiz->WriteBack             = IDirectFBImageProvider_WriteBack;
 }
      
-- 
1.5.6.3

diff --git a/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c 
b/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
index b5956aa..7d6298a 100644
--- a/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
+++ b/interfaces/IDirectFBImageProvider/idirectfbimageprovider_jpeg.c
@@ -88,6 +88,17 @@ typedef struct {
      int                  height;
 
      CoreDFB             *core;
+
+     DFBRectangle         rect;
+     DFBRegion            clip;
+
+     /* thread stuff */
+     pthread_mutex_t      lock;
+     pthread_cond_t       cond;
+     DirectThread        *thread;
+     IDirectFBSurface    *destination;
+     DFBResult            thread_res;
+
 } IDirectFBImageProvider_JPEG_data;
 
 static DirectResult
@@ -97,6 +108,10 @@ static DirectResult
 IDirectFBImageProvider_JPEG_Release ( IDirectFBImageProvider *thiz );
 
 static DFBResult
+IDirectFBImageProvider_JPEG_SetFlags ( IDirectFBImageProvider *thiz,
+                                       DFBImageProviderFlags   flags );
+
+static DFBResult
 IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
                                       IDirectFBSurface       *destination,
                                       const DFBRectangle     *destination_rect 
);
@@ -107,6 +122,10 @@ IDirectFBImageProvider_JPEG_SetRenderCallback( 
IDirectFBImageProvider *thiz,
                                                void                   *context 
);
 
 static DFBResult
+IDirectFBImageProvider_JPEG_Sync( IDirectFBImageProvider    *thiz,
+                                  DFBImageProviderSyncFlags  flags );
+
+static DFBResult
 IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider 
*thiz,
                                                    DFBSurfaceDescription  
*dsc);
 
@@ -114,6 +133,9 @@ static DFBResult
 IDirectFBImageProvider_JPEG_GetImageDescription( IDirectFBImageProvider *thiz,
                                                  DFBImageDescription    *dsc );
 
+static void *
+JPEGrenderThread( DirectThread *thread, void *driver_data );
+
 
 #define JPEG_PROG_BUF_SIZE    0x10000
 
@@ -344,8 +366,10 @@ Construct( IDirectFBImageProvider *thiz,
 
      thiz->AddRef = IDirectFBImageProvider_JPEG_AddRef;
      thiz->Release = IDirectFBImageProvider_JPEG_Release;
+     thiz->SetFlags = IDirectFBImageProvider_JPEG_SetFlags;
      thiz->RenderTo = IDirectFBImageProvider_JPEG_RenderTo;
      thiz->SetRenderCallback = IDirectFBImageProvider_JPEG_SetRenderCallback;
+     thiz->Sync = IDirectFBImageProvider_JPEG_Sync;
      thiz->GetImageDescription 
=IDirectFBImageProvider_JPEG_GetImageDescription;
      thiz->GetSurfaceDescription =
      IDirectFBImageProvider_JPEG_GetSurfaceDescription;
@@ -359,6 +383,17 @@ IDirectFBImageProvider_JPEG_Destruct( 
IDirectFBImageProvider *thiz )
      IDirectFBImageProvider_JPEG_data *data =
                               (IDirectFBImageProvider_JPEG_data*)thiz->priv;
 
+
+     if (data->thread) {
+          /* terminate the decoding thread, if necessary... */
+          direct_thread_cancel( data->thread );
+          direct_thread_join( data->thread );
+          direct_thread_destroy( data->thread );
+
+          pthread_mutex_destroy( &data->lock );
+          pthread_cond_destroy( &data->cond );
+     }
+
      data->buffer->Release( data->buffer );
 
      if (data->image)
@@ -390,22 +425,52 @@ IDirectFBImageProvider_JPEG_Release( 
IDirectFBImageProvider *thiz )
 }
 
 static DFBResult
-IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
-                                      IDirectFBSurface       *destination,
-                                      const DFBRectangle     *dest_rect )
+IDirectFBImageProvider_JPEG_SetFlags( IDirectFBImageProvider *thiz,
+                                      DFBImageProviderFlags   flags )
+{
+     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
+
+     /* if we have decoded the image already, don't do anything... */
+     if (data->image)
+          return DFB_UNSUPPORTED;
+
+     if (flags == DIPFLAGS_NONE && data->thread) {
+          /* terminate the decoding thread, if necessary... */
+          direct_thread_cancel( data->thread );
+          direct_thread_join( data->thread );
+          direct_thread_destroy( data->thread );
+          data->thread = NULL;
+
+          pthread_cond_destroy( &data->cond );
+          pthread_mutex_destroy( &data->lock );
+     }
+     else if (flags == DIPFLAGS_BACKGROUND_DECODE && !data->thread) {
+          /* or create it */
+          pthread_cond_init( &data->cond, NULL );
+          pthread_mutex_init( &data->lock, NULL );
+          /* as long as we haven't even started yet, we are in INIT state */
+          data->thread_res = DFB_INIT;
+          data->thread = direct_thread_create( DTT_DEFAULT, JPEGrenderThread,
+                                               thiz, "JPEG" );
+     }
+
+     return DFB_OK;
+}
+
+static DFBResult
+JPEG_RenderTo( IDirectFBImageProvider_JPEG_data *data,
+               IDirectFBSurface                 *destination,
+               DFBRectangle                     *rect,
+               const DFBRegion                  *clip )
 {
      DFBResult              ret;
      bool                   direct = false;
-     DFBRegion              clip;
-     DFBRectangle           rect;
      DFBSurfacePixelFormat  format;
      IDirectFBSurface_data *dst_data;
      CoreSurface           *dst_surface;
      CoreSurfaceBufferLock  lock;
      DIRenderCallbackResult cb_result = DIRCR_OK;
 
-     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
-
      dst_data = (IDirectFBSurface_data*) destination->priv;
      if (!dst_data)
           return DFB_DEAD;
@@ -418,22 +483,8 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
      if (ret)
           return ret;
 
-     dfb_region_from_rectangle( &clip, &dst_data->area.current );
-
-     if (dest_rect) {
-          if (dest_rect->w < 1 || dest_rect->h < 1)
-               return DFB_INVARG;
-          
-          rect = *dest_rect;
-          rect.x += dst_data->area.wanted.x;
-          rect.y += dst_data->area.wanted.y;
-
-          if (!dfb_rectangle_region_intersects( &rect, &clip ))
-               return DFB_OK;
-     }
-     else {
-          rect = dst_data->area.wanted;
-     }
+     D_ASSERT( clip != NULL );
+     D_ASSERT( rect != NULL );
 
      ret = dfb_surface_lock_buffer( dst_surface, CSBR_BACK, CSAID_CPU, 
CSAF_WRITE, &lock );
      if (ret)
@@ -459,7 +510,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
 
                if (data->image) {
                     dfb_scale_linear_32( data->image, data->width, 
data->height,
-                                         lock.addr, lock.pitch, &rect, 
dst_surface, &clip );
+                                         lock.addr, lock.pitch, rect, 
dst_surface, clip );
                     dfb_surface_unlock_buffer( dst_surface, &lock );
                     if (data->render_callback) {
                          DFBRectangle r = { 0, 0, data->width, data->height };
@@ -481,7 +532,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
           jpeg_read_header(&cinfo, TRUE);
           jpeg_calc_output_dimensions(&cinfo);
 
-          if (cinfo.output_width == rect.w && cinfo.output_height == rect.h)
+          if (cinfo.output_width == rect->w && cinfo.output_height == rect->h)
                direct = true;
 
           cinfo.output_components = 3;
@@ -490,14 +541,14 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                case DSPF_NV16:
                     uv_offset = dst_surface->config.size.h * lock.pitch;
 
-                    if (direct && !rect.x && !rect.y) {
+                    if (direct && !rect->x && !rect->y) {
                          D_INFO( "JPEG: Using YCbCr color space directly! 
(%dx%d)\n",
                                  cinfo.output_width, cinfo.output_height );
                          cinfo.out_color_space = JCS_YCbCr;
                          break;
                     }
                     D_INFO( "JPEG: Going through RGB color space! (%dx%d -> 
%dx%d @%d,%d)\n",
-                            cinfo.output_width, cinfo.output_height, rect.w, 
rect.h, rect.x, rect.y );
+                            cinfo.output_width, cinfo.output_height, rect->w, 
rect->h, rect->x, rect->y );
                
                default:
                     cinfo.out_color_space = JCS_RGB;
@@ -527,7 +578,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                switch (dst_surface->config.format) {
                     case DSPF_NV16:
                          if (direct) {
-                              copy_line_nv16( lock.addr, lock.addr + 
uv_offset, *buffer, rect.w );
+                              copy_line_nv16( lock.addr, lock.addr + 
uv_offset, *buffer, rect->w );
 
                               lock.addr += lock.pitch;
 
@@ -544,9 +595,9 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
                          copy_line32( row_ptr, *buffer, data->width);
 
                          if (direct) {
-                              DFBRectangle r = { rect.x, rect.y+y, rect.w, 1 };
+                              DFBRectangle r = { rect->x, rect->y+y, rect->w, 
1 };
                               dfb_copy_buffer_32( row_ptr, lock.addr, 
lock.pitch,
-                                                  &r, dst_surface, &clip );
+                                                  &r, dst_surface, clip );
                               if (data->render_callback) {
                                    r = (DFBRectangle){ 0, y, data->width, 1 };
                                    cb_result = data->render_callback( &r, 
@@ -562,7 +613,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
 
           if (!direct) {
                dfb_scale_linear_32( data->image, data->width, data->height,
-                                    lock.addr, lock.pitch, &rect, dst_surface, 
&clip );
+                                    lock.addr, lock.pitch, rect, dst_surface, 
clip );
                if (data->render_callback) {
                     DFBRectangle r = { 0, 0, data->width, data->height };
                     cb_result = data->render_callback( &r, 
data->render_callback_context );
@@ -581,7 +632,7 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
      }
      else {
           dfb_scale_linear_32( data->image, data->width, data->height,
-                               lock.addr, lock.pitch, &rect, dst_surface, 
&clip );
+                               lock.addr, lock.pitch, rect, dst_surface, clip 
);
           if (data->render_callback) {
                DFBRectangle r = { 0, 0, data->width, data->height };
                data->render_callback( &r, data->render_callback_context );
@@ -597,6 +648,65 @@ IDirectFBImageProvider_JPEG_RenderTo( 
IDirectFBImageProvider *thiz,
 }
 
 static DFBResult
+IDirectFBImageProvider_JPEG_RenderTo( IDirectFBImageProvider *thiz,
+                                      IDirectFBSurface       *destination,
+                                      const DFBRectangle     *dest_rect )
+{
+     IDirectFBSurface_data *dst_data;
+
+     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
+
+     dst_data = (IDirectFBSurface_data*) destination->priv;
+     if (!dst_data)
+          return DFB_DEAD;
+
+     if (data->thread)
+          pthread_mutex_lock( &data->lock );
+
+     dfb_region_from_rectangle( &data->clip, &dst_data->area.current );
+
+     if (dest_rect) {
+          if (dest_rect->w < 1 || dest_rect->h < 1) {
+               if (data->thread)
+                    pthread_mutex_unlock( &data->lock );
+               return DFB_INVARG;
+          }
+
+          data->rect = *dest_rect;
+          data->rect.x += dst_data->area.wanted.x;
+          data->rect.y += dst_data->area.wanted.y;
+
+          if (!dfb_rectangle_region_intersects( &data->rect, &data->clip )) {
+               if (data->thread)
+                    pthread_mutex_unlock( &data->lock );
+               return DFB_OK;
+          }
+     }
+     else {
+          data->rect = dst_data->area.wanted;
+     }
+
+     if (!data->thread || data->image) {
+          data->thread_res = JPEG_RenderTo( data, destination,
+                                            &data->rect, &data->clip );
+          if (data->thread)
+               pthread_mutex_unlock( &data->lock );
+          return data->thread_res;
+     }
+
+     D_ASSERT( data->destination == NULL );
+
+     destination->AddRef( destination );
+     data->destination = destination;
+
+     pthread_cond_signal( &data->cond );
+     pthread_mutex_unlock( &data->lock );
+//printf("signalled to %d\n", direct_thread_get_tid( data->thread ));
+
+     return DFB_OK;
+}
+
+static DFBResult
 IDirectFBImageProvider_JPEG_SetRenderCallback( IDirectFBImageProvider *thiz,
                                                DIRenderCallback        
callback,
                                                void                   *context 
)
@@ -610,6 +720,42 @@ IDirectFBImageProvider_JPEG_SetRenderCallback( 
IDirectFBImageProvider *thiz,
 }
 
 static DFBResult
+IDirectFBImageProvider_JPEG_Sync( IDirectFBImageProvider    *thiz,
+                                  DFBImageProviderSyncFlags  flags )
+{
+     DIRECT_INTERFACE_GET_DATA(IDirectFBImageProvider_JPEG)
+
+     switch (flags)
+       {
+       case DIPSYNCFLAGS_TRYSYNC:
+            if (data->thread) {
+                 if (data->thread_res == DFB_INIT
+                     || data->thread_res == DFB_BUSY) {
+                      /* DFB_INIT (user didn't call RenderTo() yet)
+                         DFB_BUSY (still busy decoding) */
+                      return data->thread_res;
+                 }
+                 /* else we are done, either because of some error or because
+                    we have processed all the data already */
+            }
+            /* fall through */
+
+       case DIPSYNCFLAGS_SYNC:
+            if (data->thread) {
+                 direct_thread_join( data->thread );
+                 direct_thread_destroy( data->thread );
+                 data->thread = NULL;
+            }
+            break;
+
+       default:
+            return DFB_OK;
+       }
+
+     return data->thread_res;
+}
+
+static DFBResult
 IDirectFBImageProvider_JPEG_GetSurfaceDescription( IDirectFBImageProvider 
*thiz,
                                                    DFBSurfaceDescription  *dsc 
)
 {
@@ -637,3 +783,58 @@ IDirectFBImageProvider_JPEG_GetImageDescription( 
IDirectFBImageProvider *thiz,
      return DFB_OK;
 }
 
+static void
+render_cleanup( void *cleanup_data )
+{
+     IDirectFBImageProvider           *thiz = cleanup_data;
+     IDirectFBImageProvider_JPEG_data *data;
+
+     D_MAGIC_ASSERT( (IAny*)thiz, DirectInterface );
+     data = (IDirectFBImageProvider_JPEG_data *) thiz->priv;
+     D_ASSERT( data != NULL );
+
+     if (data->destination) {
+          data->destination->Release( data->destination );
+          data->destination = NULL;
+     }
+
+     /* in case we get terminated from outside, set the state to DFB_DEAD */
+     data->thread_res = DFB_DEAD;
+
+     pthread_mutex_unlock( &data->lock );
+}
+
+static void *
+JPEGrenderThread( DirectThread *thread, void *driver_data )
+{
+     IDirectFBImageProvider           *thiz = driver_data;
+     IDirectFBImageProvider_JPEG_data *data;
+     DFBResult res;
+
+     D_MAGIC_ASSERT( (IAny*)thiz, DirectInterface );
+     data = (IDirectFBImageProvider_JPEG_data *) thiz->priv;
+     D_ASSERT( data != NULL );
+
+//printf("%d is starting\n", direct_gettid ());
+     pthread_mutex_lock( &data->lock );
+
+     pthread_cleanup_push( render_cleanup, thiz );
+
+     while (!data->destination) {
+//printf("%d is waiting\n", direct_gettid ());
+          pthread_cond_wait( &data->cond, &data->lock );
+     }
+//printf("%d is running\n", direct_gettid ());
+
+     /* as long as we haven't finished decoding we are busy */
+     data->thread_res = DFB_BUSY;
+
+     res = JPEG_RenderTo( data, data->destination, &data->rect, &data->clip );
+
+     pthread_cleanup_pop( 1 );
+
+     /* in case we exit normally, apply the real return value */
+     data->thread_res = res;
+
+     return NULL;
+}
_______________________________________________
directfb-dev mailing list
directfb-dev@directfb.org
http://mail.directfb.org/cgi-bin/mailman/listinfo/directfb-dev

Reply via email to