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