bool
davinciStretchBlit32( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect )
{
     DavinciDriverData *ddrv = drv;
     DavinciDeviceData *ddev = dev;

     DFBRegion clip = DFB_REGION_INIT_FROM_RECTANGLE( drect );

     D_DEBUG_AT( Davinci_2D, "%s( %4d,%4d-%4dx%4d <- %4d,%4d-%4dx%4d )\n",
                 __FUNCTION__, DFB_RECTANGLE_VALS(drect), DFB_RECTANGLE_VALS(srect) );

     if (!dfb_region_region_intersect( &clip, &ddev->clip ))
          return true;

     dfb_region_translate( &clip, -drect->x, -drect->y );

     davinci_c64x_stretch_32__L( &ddrv->tasks,
                                 ddev->dst_phys + ddev->dst_pitch * drect->y + ddev->dst_bpp * drect->x,
                                 ddev->dst_pitch,
                                 ddev->src_phys + ddev->src_pitch * srect->y + ddev->src_bpp * srect->x,
                                 ddev->src_pitch,
                                 drect->w, drect->h,
                                 srect->w, srect->h,
                                 &clip );

     return true;
}
static bool
stretch_hvx( CardState *state, DFBRectangle *srect, DFBRectangle *drect )
{
     GenefxState                *gfxs;
     const StretchFunctionTable *table;
     StretchHVx                  stretch;
     bool                        down = false;
     void                       *dst;
     void                       *src;
     StretchCtx                  ctx;
     int                         idx = STRETCH_NONE;
     u32                         colors[256];

     D_ASSERT( state != NULL );
     DFB_RECTANGLE_ASSERT( srect );
     DFB_RECTANGLE_ASSERT( drect );

     gfxs = state->gfxs;

     if (srect->w > drect->w && srect->h > drect->h)
          down = true;

     if (down) {
          if (!(state->render_options & DSRO_SMOOTH_DOWNSCALE))
               return false;
     }
     else {
          if (!(state->render_options & DSRO_SMOOTH_UPSCALE))
               return false;
     }

     switch (gfxs->dst_format) {
          case DSPF_NV12:
          case DSPF_NV21:
               return stretch_hvx_planar( state, srect, drect, down );

          default:
               break;
     }

     if (state->blittingflags & ~(DSBLIT_COLORKEY_PROTECT | DSBLIT_SRC_COLORKEY | DSBLIT_SRC_PREMULTIPLY))
          return false;

     if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY && !DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format ))
          return false;

     if (DFB_PIXELFORMAT_INDEX(gfxs->dst_format) >= D_ARRAY_SIZE(stretch_tables))
          return false;

     if (DFB_PIXELFORMAT_INDEX(gfxs->src_format) >= D_ARRAY_SIZE((stretch_tables[0])->f))
          return false;

     table = stretch_tables[DFB_PIXELFORMAT_INDEX(gfxs->dst_format)];
     if (!table)
          return false;

     if (state->blittingflags & DSBLIT_SRC_COLORKEY)
          idx |= STRETCH_SRCKEY;

     if (state->blittingflags & DSBLIT_COLORKEY_PROTECT)
          idx |= STRETCH_PROTECT;

     if (down)
          stretch = table->f[DFB_PIXELFORMAT_INDEX(gfxs->src_format)].down[idx];
     else
          stretch = table->f[DFB_PIXELFORMAT_INDEX(gfxs->src_format)].up[idx];

     if (!stretch)
          return false;

     ctx.clip = state->clip;

     if (!dfb_region_rectangle_intersect( &ctx.clip, drect ))
          return false;

     dfb_region_translate( &ctx.clip, - drect->x, - drect->y );

     if (DFB_PIXELFORMAT_IS_INDEXED( gfxs->src_format )) {
          int             i;
          const DFBColor *entries;
          u16            *colors16 = (void*) colors;

          D_ASSERT( gfxs->Blut != NULL );

          entries = gfxs->Blut->entries;

          switch (gfxs->dst_format) {
               case DSPF_ARGB:
                    if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) {
                         for (i=0; i<gfxs->Blut->num_entries; i++) {
                              int alpha = entries[i].a + 1;

                              switch (alpha) {
                                   case 0:
                                        colors[i] = 0;
                                        break;

                                   case 255:
                                        colors[i] = PIXEL_ARGB( entries[i].a,
                                                                entries[i].r,
                                                                entries[i].g,
                                                                entries[i].b );
                                        break;

                                   default:
                                        colors[i] = PIXEL_ARGB( entries[i].a,
                                                                (alpha * entries[i].r) >> 8,
                                                                (alpha * entries[i].g) >> 8,
                                                                (alpha * entries[i].b) >> 8 );
                              }
                         }
                    }
                    else {
                         for (i=0; i<gfxs->Blut->num_entries; i++)
                              colors[i] = PIXEL_ARGB( entries[i].a, entries[i].r, entries[i].g, entries[i].b );
                    }
                    break;

               case DSPF_RGB32:
                    for (i=0; i<gfxs->Blut->num_entries; i++)
                         colors[i] = PIXEL_RGB32( entries[i].r, entries[i].g, entries[i].b );
                    break;

               case DSPF_RGB16:
                    for (i=0; i<gfxs->Blut->num_entries; i++)
                         colors16[i] = PIXEL_RGB16( entries[i].r, entries[i].g, entries[i].b );
                    break;

               case DSPF_ARGB4444:
                    if (state->blittingflags & DSBLIT_SRC_PREMULTIPLY) {
                         for (i=0; i<gfxs->Blut->num_entries; i++) {
                              int alpha = entries[i].a + 1;

                              switch (alpha) {
                                   case 0:
                                        colors16[i] = 0;
                                        break;

                                   case 255:
                                        colors16[i] = PIXEL_ARGB4444( entries[i].a,
                                                                      entries[i].r,
                                                                      entries[i].g,
                                                                      entries[i].b );
                                        break;

                                   default:
                                        colors16[i] = PIXEL_ARGB4444( entries[i].a,
                                                                      (alpha * entries[i].r) >> 8,
                                                                      (alpha * entries[i].g) >> 8,
                                                                      (alpha * entries[i].b) >> 8 );
                              }
                         }
                    }
                    else {
                         for (i=0; i<gfxs->Blut->num_entries; i++)
static bool
stretch_hvx_planar( CardState *state, DFBRectangle *srect, DFBRectangle *drect, bool down )
{
     GenefxState *gfxs;
     void        *dst;
     void        *src;
     DFBRegion    clip;

     D_ASSERT( state != NULL );
     DFB_RECTANGLE_ASSERT( srect );
     DFB_RECTANGLE_ASSERT( drect );

     gfxs = state->gfxs;

     if (state->blittingflags)
          return false;

     if (gfxs->dst_format != gfxs->src_format)
          return false;

     clip = state->clip;

     if (!dfb_region_rectangle_intersect( &clip, drect ))
          return false;

     dfb_region_translate( &clip, - drect->x, - drect->y );

     dst = gfxs->dst_org[0] + drect->y * gfxs->dst_pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, drect->x );
     src = gfxs->src_org[0] + srect->y * gfxs->src_pitch + DFB_BYTES_PER_LINE( gfxs->src_format, srect->x );

     switch (gfxs->dst_format) {
          case DSPF_NV12:
          case DSPF_NV21:
               if (down)
                    stretch_hvx_8_down( dst, gfxs->dst_pitch, src, gfxs->src_pitch,
                                        srect->w, srect->h, drect->w, drect->h, &clip );
               else
                    stretch_hvx_8_up( dst, gfxs->dst_pitch, src, gfxs->src_pitch,
                                      srect->w, srect->h, drect->w, drect->h, &clip );

               clip.x1 /= 2;
               clip.x2 /= 2;
               clip.y1 /= 2;
               clip.y2 /= 2;

               dst = gfxs->dst_org[1] + drect->y/2 * gfxs->dst_pitch + DFB_BYTES_PER_LINE( gfxs->dst_format, drect->x );
               src = gfxs->src_org[1] + srect->y/2 * gfxs->src_pitch + DFB_BYTES_PER_LINE( gfxs->src_format, srect->x );

               if (down)
                    stretch_hvx_88_down( dst, gfxs->dst_pitch, src, gfxs->src_pitch,
                                         srect->w/2, srect->h, drect->w/2, drect->h, &clip );
               else
                    stretch_hvx_88_up( dst, gfxs->dst_pitch, src, gfxs->src_pitch,
                                       srect->w/2, srect->h, drect->w/2, drect->h, &clip );
               break;

          default:
               break;
     }

     return true;
}