From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/src/misc/gfx_util.c | 964 ++++++++++++++++++++++++++++++++++++ 1 file changed, 964 insertions(+) create mode 100755 Source/DirectFB/src/misc/gfx_util.c (limited to 'Source/DirectFB/src/misc/gfx_util.c') diff --git a/Source/DirectFB/src/misc/gfx_util.c b/Source/DirectFB/src/misc/gfx_util.c new file mode 100755 index 0000000..1165112 --- /dev/null +++ b/Source/DirectFB/src/misc/gfx_util.c @@ -0,0 +1,964 @@ +/* + (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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + Scaling routines ported from gdk_pixbuf by Sven Neumann + . + + 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 + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#define SUBSAMPLE_BITS 4 +#define SUBSAMPLE (1 << SUBSAMPLE_BITS) +#define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1) +#define SCALE_SHIFT 16 + + +typedef struct _PixopsFilter PixopsFilter; + +struct _PixopsFilter { + int *weights; + int n_x; + int n_y; + float x_offset; + float y_offset; +}; + + +static void write_argb_span (u32 *src, u8 *dst[], int len, + int dx, int dy, CoreSurface *dst_surface) +{ + CorePalette *palette = dst_surface->palette; + u8 *d = dst[0]; + u8 *d1,*d2; + int i, j; + + if (dst_surface->config.caps & DSCAPS_PREMULTIPLIED) { + for (i = 0; i < len; i++) { + const u32 s = src[i]; + const u32 a = (s >> 24) + 1; + + src[i] = ((((s & 0x00ff00ff) * a) >> 8) & 0x00ff00ff) | + ((((s & 0x0000ff00) * a) >> 8) & 0x0000ff00) | + ((((s & 0xff000000) ) ) ); + } + } + + switch (dst_surface->config.format) { + case DSPF_A1: + for (i = 0; i < len; i++) { + if (i & 7) + d[i>>3] |= (src[i] >> 31) << (7-(i&7)); + else + d[i>>3] = (src[i] >> 24) & 0x80; + } + break; + + case DSPF_A4: + for (i = 0, j = 0; i < len; i += 2, j++) + d[j] = ((src[i] >> 24) & 0xF0) | (src[i+1] >> 28); + break; + + case DSPF_A8: + for (i = 0; i < len; i++) + d[i] = src[i] >> 24; + break; + + case DSPF_RGB332: + for (i = 0; i < len; i++) + d[i] = RGB32_TO_RGB332( src[i] ); + break; + + case DSPF_ARGB1555: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_ARGB1555( src[i] ); + break; + + case DSPF_ARGB2554: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_ARGB2554( src[i] ); + break; + + case DSPF_ARGB4444: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_ARGB4444( src[i] ); + break; + + case DSPF_RGBA4444: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_RGBA4444( src[i] ); + break; + + case DSPF_RGB16: +#ifdef DFB_DITHER565 + /* use a pre-generated dither matrix to improve the appearance of the result */ + { + const u32 *dm = DM_565 + ((dy & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT); + + for (i = 0; i < len; i++) { + u32 rgb = ((src[i] & 0xFF) | + (src[i] & 0xFF00) << 2 | + (src[i] & 0xFF0000) << 4); + + rgb += dm[(dx + i) & (DM_WIDTH - 1)]; + rgb += (0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6)); + + ((u16*)d)[i] = (((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3)); + } + } +#else + for (i = 0; i < len; i++) + ((u16*)d)[i] = RGB32_TO_RGB16( src[i] ); +#endif + break; + + case DSPF_ARGB1666: + for (i = 0; i < len; i++) { + const u32 pixel = PIXEL_ARGB1666( src[i] >> 24, + src[i] >> 16, + src[i] >> 8, + src[i] ); + + *d++ = pixel; + *d++ = pixel >> 8; + *d++ = pixel >> 16; + } + break; + + case DSPF_ARGB6666: + for (i = 0; i < len; i++) { + const u32 pixel = PIXEL_ARGB6666( src[i] >> 24, + src[i] >> 16, + src[i] >> 8, + src[i] ); + + *d++ = pixel; + *d++ = pixel >> 8; + *d++ = pixel >> 16; + } + break; + + case DSPF_RGB18: + for (i = 0; i < len; i++) { + const u32 pixel = PIXEL_RGB18( src[i] >> 16, + src[i] >> 8, + src[i] ); + + *d++ = pixel; + *d++ = pixel >> 8; + *d++ = pixel >> 16; + } + break; + + case DSPF_RGB24: + for (i = 0; i < len; i++) { +#ifdef WORDS_BIGENDIAN + *d++ = src[i] >> 16; + *d++ = src[i] >> 8; + *d++ = src[i]; +#else + *d++ = src[i]; + *d++ = src[i] >> 8; + *d++ = src[i] >> 16; +#endif + } + break; + + case DSPF_RGB32: + case DSPF_ARGB: + direct_memcpy( d, src, len*4 ); + break; + + case DSPF_AiRGB: + for (i = 0; i < len; i++) + ((u32*)d)[i] = src[i] ^ 0xff000000; + break; + + case DSPF_LUT8: + if (palette) { + for (i = 0; i < len; i++) { + d[i] = dfb_palette_search( palette, + (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, + (src[i] >> 24) & 0xff ); + } + } + break; + + case DSPF_ALUT44: + if (palette) { + for (i = 0; i < len; i++) { + d[i] = ((src[i] >> 24) & 0xf0) + + dfb_palette_search( palette, + (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, 0x80 ); + } + } + break; + + case DSPF_YUY2: + if (dx & 1) { + u32 y, u, v; + + RGB_TO_YCBCR( (src[0] >> 16) & 0xff, + (src[0] >> 8) & 0xff, + (src[0] ) & 0xff, y, u, v ); + *((u16*)d) = y | (v << 8); + d += 2; + src++; + len--; + } + for (i = 0; i < (len-1); i += 2) { + u32 y0, u, v; + u32 y1, u1, v1; + + RGB_TO_YCBCR( (src[i+0] >> 16) & 0xff, + (src[i+0] >> 8) & 0xff, + (src[i+0] ) & 0xff, y0, u, v ); + RGB_TO_YCBCR( (src[i+1] >> 16) & 0xff, + (src[i+1] >> 8) & 0xff, + (src[i+1] ) & 0xff, y1, u1, v1 ); + + u = (u + u1) >> 1; + v = (v + v1) >> 1; + + ((u16*)d)[i+0] = y0 | (u << 8); + ((u16*)d)[i+1] = y1 | (v << 8); + } + if (len & 1) { + u32 y, u, v; + + src += len-1; + d += (len-1) * 2; + + RGB_TO_YCBCR( (*src >> 16) & 0xff, + (*src >> 8) & 0xff, + (*src ) & 0xff, y, u, v ); + *((u16*)d) = y | (u << 8); + } + break; + + case DSPF_UYVY: + if (dx & 1) { + u32 y, u, v; + + RGB_TO_YCBCR( (src[0] >> 16) & 0xff, + (src[0] >> 8) & 0xff, + (src[0] ) & 0xff, y, u, v ); + *((u16*)d) = v | (y << 8); + d += 2; + src++; + len--; + } + for (i = 0; i < (len-1); i += 2) { + u32 y0, u, v; + u32 y1, u1, v1; + + RGB_TO_YCBCR( (src[i+0] >> 16) & 0xff, + (src[i+0] >> 8) & 0xff, + (src[i+0] ) & 0xff, y0, u, v ); + RGB_TO_YCBCR( (src[i+1] >> 16) & 0xff, + (src[i+1] >> 8) & 0xff, + (src[i+1] ) & 0xff, y1, u1, v1 ); + + u = (u + u1) >> 1; + v = (v + v1) >> 1; + + ((u16*)d)[i+0] = u | (y0 << 8); + ((u16*)d)[i+1] = v | (y1 << 8); + } + if (len & 1) { + u32 y, u, v; + + src += len-1; + d += (len-1) * 2; + + RGB_TO_YCBCR( (*src >> 16) & 0xff, + (*src >> 8) & 0xff, + (*src ) & 0xff, y, u, v ); + *((u16*)d) = u | (y << 8); + } + break; + + case DSPF_AYUV: + for (i = 0; i < len; i++) { + u32 a, y, u, v; + + RGB_TO_YCBCR( (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, y, u, v ); + a = (src[i] >> 24) & 0xff; + + ((u32*)d)[i] = PIXEL_AYUV( a, y, u, v ); + } + break; + + case DSPF_YV12: + case DSPF_I420: + d1 = dst[1]; + d2 = dst[2]; + for (i = 0; i < (len-1); i += 2) { + u32 y0, u0, v0; + u32 y1, u1, v1; + + RGB_TO_YCBCR( (src[i+0] >> 16) & 0xff, + (src[i+0] >> 8) & 0xff, + (src[i+0] ) & 0xff, y0, u0, v0 ); + RGB_TO_YCBCR( (src[i+1] >> 16) & 0xff, + (src[i+1] >> 8) & 0xff, + (src[i+1] ) & 0xff, y1, u1, v1 ); + + d[i+0] = y0; + d[i+1] = y1; + + if (dy & 1) { + d1[i>>1] = (u0 + u1) >> 1; + d2[i>>1] = (v0 + v1) >> 1; + } + } + if (len & 1) { + u32 y, u, v; + + i = len-1; + + RGB_TO_YCBCR( (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, y, u, v ); + + d[i] = y; + if (dy & 1) { + d1[i>>1] = u; + d2[i>>1] = v; + } + } + break; + + case DSPF_NV12: + case DSPF_NV16: + d1 = dst[1]; + for (i = 0; i < (len-1); i += 2) { + u32 y0, u0, v0; + u32 y1, u1, v1; + + RGB_TO_YCBCR( (src[i+0] >> 16) & 0xff, + (src[i+0] >> 8) & 0xff, + (src[i+0] ) & 0xff, y0, u0, v0 ); + RGB_TO_YCBCR( (src[i+1] >> 16) & 0xff, + (src[i+1] >> 8) & 0xff, + (src[i+1] ) & 0xff, y1, u1, v1 ); + + d[i+0] = y0; + d[i+1] = y1; + + if (dst_surface->config.format == DSPF_NV16 || dy & 1) { +#ifdef WORDS_BIGENDIAN + ((u16*)d1)[i>>1] = ((v0 + v1) >> 1) | + (((u0 + u1) >> 1) << 8); +#else + ((u16*)d1)[i>>1] = ((u0 + u1) >> 1) | + (((v0 + v1) >> 1) << 8); +#endif + } + } + if (len & 1) { + u32 y, u, v; + + i = len-1; + + RGB_TO_YCBCR( (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, y, u, v ); + + d[i] = y; + if (dst_surface->config.format == DSPF_NV16 || dy & 1) +#ifdef WORDS_BIGENDIAN + ((u16*)d1)[i>>1] = v | (u << 8); +#else + ((u16*)d1)[i>>1] = u | (v << 8); +#endif + } + break; + + case DSPF_NV21: + d1 = dst[1]; + for (i = 0; i < (len-1); i += 2) { + u32 y0, u0, v0; + u32 y1, u1, v1; + + RGB_TO_YCBCR( (src[i+0] >> 16) & 0xff, + (src[i+0] >> 8) & 0xff, + (src[i+0] ) & 0xff, y0, u0, v0 ); + RGB_TO_YCBCR( (src[i+1] >> 16) & 0xff, + (src[i+1] >> 8) & 0xff, + (src[i+1] ) & 0xff, y1, u1, v1 ); + + d[i+0] = y0; + d[i+1] = y1; + + if (dy & 1) { +#ifdef WORDS_BIGENDIAN + ((u16*)d1)[i>>1] = ((u0 + u1) >> 1) | + (((v0 + v1) >> 1) << 8); +#else + ((u16*)d1)[i>>1] = ((v0 + v1) >> 1) | + (((u0 + u1) >> 1) << 8); +#endif + } + } + if (len & 1) { + u32 y, u, v; + + i = len-1; + + RGB_TO_YCBCR( (src[i] >> 16) & 0xff, + (src[i] >> 8) & 0xff, + (src[i] ) & 0xff, y, u, v ); + + d[i] = y; + if (dy & 1) +#ifdef WORDS_BIGENDIAN + ((u16*)d1)[i>>1] = u | (v << 8); +#else + ((u16*)d1)[i>>1] = v | (u << 8); +#endif + } + break; + + case DSPF_RGB555: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_RGB555( src[i] ); + break; + + case DSPF_BGR555: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_BGR555( src[i] ); + break; + + case DSPF_RGB444: + for (i = 0; i < len; i++) + ((u16*)d)[i] = ARGB_TO_RGB444( src[i] ); + break; + + default: + D_ONCE( "unimplemented destination format (0x%08x)", dst_surface->config.format ); + break; + } +} + +#define LINE_PTR(dst,caps,y,h,pitch) \ + ((caps & DSCAPS_SEPARATED) \ + ? (((u8*)(dst)) + (y)/2 * (pitch) + (((y)%2) ? (h)/2 * (pitch) : 0)) \ + : (((u8*)(dst)) + (y) * (pitch))) + +void dfb_copy_buffer_32( u32 *src, + void *dst, int dpitch, DFBRectangle *drect, + CoreSurface *dst_surface, const DFBRegion *dst_clip ) +{ + void *dst1, *dst2; + int sw = drect->w; + int y, x; + + if (dst_clip) { + int sx = 0, sy = 0; + + if (drect->x < dst_clip->x1) { + sx = dst_clip->x1 - drect->x; + drect->w -= sx; + drect->x += sx; + } + if (drect->y < dst_clip->y1) { + sy = dst_clip->y1 - drect->y; + drect->h -= sy; + drect->y += sy; + } + if ((drect->x + drect->w - 1) > dst_clip->x2) { + drect->w -= drect->x + drect->w - 1 - dst_clip->x2; + } + if ((drect->y + drect->h - 1) > dst_clip->y2) { + drect->h -= drect->y + drect-> h - 1 - dst_clip->y2; + } + + src += sy * sw + sx; + } + + if (drect->w < 1 || drect->h < 1) + return; + x = drect->x; + + switch (dst_surface->config.format) { + case DSPF_YV12: + case DSPF_I420: + if (dst_surface->config.format == DSPF_I420) { + dst1 = dst + dpitch * dst_surface->config.size.h; + dst2 = dst1 + dpitch/2 * dst_surface->config.size.h/2; + } else { + dst2 = dst + dpitch * dst_surface->config.size.h; + dst1 = dst2 + dpitch/2 * dst_surface->config.size.h/2; + } + + for (y = drect->y; y < drect->y + drect->h; y++) { + u8 *d[3]; + + d[0] = LINE_PTR( dst, dst_surface->config.caps, y, + dst_surface->config.size.h, dpitch ) + x; + d[1] = LINE_PTR( dst1, dst_surface->config.caps, y/2, + dst_surface->config.size.h/2, dpitch/2 ) + x/2; + d[2] = LINE_PTR( dst2, dst_surface->config.caps, y/2, + dst_surface->config.size.h/2, dpitch/2 ) + x/2; + + write_argb_span( src, d, drect->w, x, y, dst_surface ); + + src += sw; + } + break; + + case DSPF_NV12: + case DSPF_NV21: + dst1 = dst + dpitch * dst_surface->config.size.h; + + for (y = drect->y; y < drect->y + drect->h; y++) { + u8 *d[2]; + + d[0] = LINE_PTR( dst, dst_surface->config.caps, y, + dst_surface->config.size.h, dpitch ) + x; + d[1] = LINE_PTR( dst1, dst_surface->config.caps, y/2, + dst_surface->config.size.h/2, dpitch ) + (x&~1); + + write_argb_span( src, d, drect->w, x, y, dst_surface ); + + src += sw; + } + break; + + case DSPF_NV16: + dst1 = dst + dpitch * dst_surface->config.size.h; + + for (y = drect->y; y < drect->y + drect->h; y++) { + u8 *d[2]; + + d[0] = LINE_PTR( dst, dst_surface->config.caps, y, + dst_surface->config.size.h, dpitch ) + x; + d[1] = LINE_PTR( dst1, dst_surface->config.caps, y, + dst_surface->config.size.h, dpitch ) + (x&~1); + + write_argb_span( src, d, drect->w, x, y, dst_surface ); + + src += sw; + } + break; + + default: + for (y = drect->y; y < drect->y + drect->h; y++) { + u8 *d[1]; + + d[0] = LINE_PTR( dst, dst_surface->config.caps, + y, dst_surface->config.size.h, dpitch ) + + DFB_BYTES_PER_LINE( dst_surface->config.format, x ); + + write_argb_span( src, d, drect->w, x, y, dst_surface ); + + src += sw; + } + break; + } +} + +static int bilinear_make_fast_weights( PixopsFilter *filter, + const float x_scale, const float y_scale ) +{ + int i_offset, j_offset; + float *x_weights, *y_weights; + int n_x, n_y; + + if (x_scale > 1.0) { /* Bilinear */ + n_x = 2; + filter->x_offset = 0.5 * (1.0 / x_scale - 1); + } + else { /* Tile */ + n_x = D_ICEIL (1.0 + 1.0 / x_scale); + filter->x_offset = 0.0; + } + + if (y_scale > 1.0) { /* Bilinear */ + n_y = 2; + filter->y_offset = 0.5 * (1.0 / y_scale - 1); + } + else { /* Tile */ + n_y = D_ICEIL (1.0 + 1.0 / y_scale); + filter->y_offset = 0.0; + } + + if (n_x > 64) + n_x = 64; + + if (n_y > 64) + n_y = 64; + + filter->n_y = n_y; + filter->n_x = n_x; + filter->weights = (int *) D_MALLOC( SUBSAMPLE * SUBSAMPLE * n_x * n_y * + sizeof (int) ); + if (!filter->weights) { + D_WARN ("couldn't allocate memory for scaling"); + return 0; + } + + x_weights = (float *) alloca (n_x * sizeof (float)); + y_weights = (float *) alloca (n_y * sizeof (float)); + + if (!x_weights || !y_weights) { + D_FREE( filter->weights ); + + D_WARN ("couldn't allocate memory for scaling"); + return 0; + } + + for (i_offset = 0; i_offset < SUBSAMPLE; i_offset++) + for (j_offset = 0; j_offset < SUBSAMPLE; j_offset++) { + int *pixel_weights = filter->weights + + ((i_offset * SUBSAMPLE) + j_offset) + * n_x * n_y; + + float x = (float)j_offset / 16; + float y = (float)i_offset / 16; + int i, j; + + if (x_scale > 1.0) { /* Bilinear */ + for (i = 0; i < n_x; i++) { + x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale; + } + } + else { /* Tile */ + for (i = 0; i < n_x; i++) { + if (i < x) { + if (i + 1 > x) + x_weights[i] = MIN( i + 1, x + 1.0 / x_scale ) -x; + else + x_weights[i] = 0; + } + else { + if (x + 1/x_scale > i) + x_weights[i] = MIN( i + 1, x + 1.0 / x_scale ) -i; + else + x_weights[i] = 0; + } + } + } + + if (y_scale > 1.0) { /* Bilinear */ + for (i = 0; i < n_y; i++) { + y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale; + } + } + else { /* Tile */ + for (i = 0; i < n_y; i++) { + if (i < y) { + if (i + 1 > y) + y_weights[i] = MIN( i + 1, y + 1.0 / y_scale ) -y; + else + y_weights[i] = 0; + } + else { + if (y + 1/y_scale > i) + y_weights[i] = MIN( i + 1, y + 1.0 / y_scale ) -i; + else + y_weights[i] = 0; + } + } + } + + for (i = 0; i < n_y; i++) { + for (j = 0; j < n_x; j++) { + pixel_weights[n_x * i + j] = + 65536.0 * x_weights[j] * x_scale + * y_weights[i] * y_scale; + } + } + } + + return 1; +} + +static void scale_pixel( const int *weights, int n_x, int n_y, + u32 *dst, const u32 **src, int x, int sw ) +{ + u32 r = 0, g = 0, b = 0, a = 0; + int i, j; + + for (i = 0; i < n_y; i++) { + const int *pixel_weights = weights + n_x * i; + + for (j = 0; j < n_x; j++) { + const u32 *q; + + if (x + j < 0) + q = src[i]; + else if (x + j < sw) + q = src[i] + x + j; + else + q = src[i] + sw - 1; + + { + const u32 ta = ((*q & 0xFF000000) >> 24) * pixel_weights[j]; + + b += ta * (((*q & 0xFF)) + 1); + g += ta * (((*q & 0xFF00) >> 8) + 1); + r += ta * (((*q & 0xFF0000) >> 16) + 1); + a += ta; + } + } + } + + r = (r >> 24) == 0xFF ? 0xFF : (r + 0x800000) >> 24; + g = (g >> 24) == 0xFF ? 0xFF : (g + 0x800000) >> 24; + b = (b >> 24) == 0xFF ? 0xFF : (b + 0x800000) >> 24; + a = (a >> 16) == 0xFF ? 0xFF : (a + 0x8000) >> 16; + + *dst = (a << 24) | (r << 16) | (g << 8) | b; +} + +static u32* scale_line( const int *weights, int n_x, int n_y, + u32 *dst, u32 *dst_end, + const u32 **src, int x, int x_step, int sw ) +{ + while (dst < dst_end) { + const int x_scaled = x >> SCALE_SHIFT; + const int *pixel_weights = weights + ((x >> (SCALE_SHIFT - + SUBSAMPLE_BITS)) + & SUBSAMPLE_MASK) * n_x * n_y; + u32 r = 0, g = 0, b = 0, a = 0; + int i, j; + + for (i = 0; i < n_y; i++) { + const int *line_weights = pixel_weights + n_x * i; + const u32 *q = src[i] + x_scaled; + + for (j = 0; j < n_x; j++) { + const u32 ta = ((*q & 0xFF000000) >> 24) * line_weights[j]; + + b += ta * (((*q & 0xFF)) + 1); + g += ta * (((*q & 0xFF00) >> 8) + 1); + r += ta * (((*q & 0xFF0000) >> 16) + 1); + a += ta; + + q++; + } + } + + r = (r >> 24) == 0xFF ? 0xFF : (r + 0x800000) >> 24; + g = (g >> 24) == 0xFF ? 0xFF : (g + 0x800000) >> 24; + b = (b >> 24) == 0xFF ? 0xFF : (b + 0x800000) >> 24; + a = (a >> 16) == 0xFF ? 0xFF : (a + 0x8000) >> 16; + + *dst++ = (a << 24) | (r << 16) | (g << 8) | b; + + x += x_step; + } + + return dst; +} + +void dfb_scale_linear_32( u32 *src, int sw, int sh, + void *dst, int dpitch, DFBRectangle *drect, + CoreSurface *dst_surface, const DFBRegion *dst_clip ) +{ + DFBRectangle srect = { 0, 0, sw, sh }; + float scale_x, scale_y; + int i, j; + int sx, sy; + int x_step, y_step; + int scaled_x_offset; + PixopsFilter filter; + void *dst1 = NULL, *dst2 = NULL; + u32 *buf; + + if (drect->w == sw && drect->h == sh) { + dfb_copy_buffer_32( src, dst, dpitch, drect, dst_surface, dst_clip ); + return; + } + + if (dst_clip) + dfb_clip_stretchblit( dst_clip, &srect, drect ); + + if (srect.w < 1 || srect.h < 1 || drect->w < 1 || drect->h < 1) + return; + + src += srect.y * sw + srect.x; + + scale_x = (float)drect->w / srect.w; + scale_y = (float)drect->h / srect.h; + + x_step = (1 << SCALE_SHIFT) / scale_x; + y_step = (1 << SCALE_SHIFT) / scale_y; + + if (! bilinear_make_fast_weights( &filter, scale_x, scale_y )) + return; + + scaled_x_offset = D_IFLOOR( filter.x_offset * (1 << SCALE_SHIFT) ); + sy = D_IFLOOR( filter.y_offset * (1 << SCALE_SHIFT) ); + + switch (dst_surface->config.format) { + case DSPF_I420: + dst1 = dst + dpitch * dst_surface->config.size.h; + dst2 = dst1 + dpitch/2 * dst_surface->config.size.h/2; + break; + case DSPF_YV12: + dst2 = dst + dpitch * dst_surface->config.size.h; + dst1 = dst2 + dpitch/2 * dst_surface->config.size.h/2; + break; + case DSPF_NV12: + case DSPF_NV21: + case DSPF_NV16: + dst1 = dst + dpitch * dst_surface->config.size.h; + break; + default: + break; + } + + buf = (u32*) alloca( drect->w * 4 ); + + for (i = drect->y; i < drect->y + drect->h; i++) { + int x_start; + int y_start; + const int *run_weights; + u32 *outbuf = buf; + u32 *outbuf_end = buf + drect->w; + u32 *new_outbuf; + const u32 **line_bufs; + u8 *d[3]; + + y_start = sy >> SCALE_SHIFT; + + run_weights = filter.weights + ((sy >> (SCALE_SHIFT - SUBSAMPLE_BITS)) + & SUBSAMPLE_MASK) * filter.n_x * filter.n_y * SUBSAMPLE; + + line_bufs = (const u32 **) alloca( filter.n_y * sizeof (void *) ); + + for (j = 0; j < filter.n_y; j++) { + if (y_start < 0) + line_bufs[j] = src; + else if (y_start < sh) + line_bufs[j] = src + sw * y_start; + else + line_bufs[j] = src + sw * (sh - 1); + + y_start++; + } + + sx = scaled_x_offset; + x_start = sx >> SCALE_SHIFT; + + while (x_start < 0 && outbuf < outbuf_end) { + scale_pixel( run_weights + ((sx >> (SCALE_SHIFT - SUBSAMPLE_BITS)) + & SUBSAMPLE_MASK) * (filter.n_x * filter.n_y), + filter.n_x, filter.n_y, + outbuf, line_bufs, sx >> SCALE_SHIFT, sw ); + sx += x_step; + x_start = sx >> SCALE_SHIFT; + outbuf++; + } + + new_outbuf = scale_line( run_weights, filter.n_x, filter.n_y, + outbuf, outbuf_end, line_bufs, + sx >> SCALE_SHIFT, x_step, sw ); + sx = ((outbuf_end - outbuf) >> 2) * x_step + scaled_x_offset; + outbuf = new_outbuf; + + while (outbuf < outbuf_end) { + scale_pixel( run_weights + ((sx >> (SCALE_SHIFT - SUBSAMPLE_BITS)) + & SUBSAMPLE_MASK) * (filter.n_x * filter.n_y), + filter.n_x, filter.n_y, + outbuf, line_bufs, sx >> SCALE_SHIFT, sw ); + sx += x_step; + outbuf++; + } + + sy += y_step; + + d[0] = LINE_PTR( dst, dst_surface->config.caps, + i, dst_surface->config.size.h, dpitch ) + + DFB_BYTES_PER_LINE( dst_surface->config.format, drect->x ); + + switch (dst_surface->config.format) { + case DSPF_I420: + case DSPF_YV12: + d[1] = LINE_PTR( dst1, dst_surface->config.caps, i/2, + dst_surface->config.size.h/2, dpitch/2 ) + drect->x/2; + d[2] = LINE_PTR( dst2, dst_surface->config.caps, i/2, + dst_surface->config.size.h/2, dpitch/2 ) + drect->x/2; + break; + case DSPF_NV12: + case DSPF_NV21: + d[1] = LINE_PTR( dst1, dst_surface->config.caps, i/2, + dst_surface->config.size.h/2, dpitch ) + (drect->x&~1); + break; + case DSPF_NV16: + d[1] = LINE_PTR( dst1, dst_surface->config.caps, i, + dst_surface->config.size.h, dpitch ) + (drect->x&~1); + break; + default: + break; + } + + write_argb_span( buf, d, drect->w, drect->x, i, dst_surface ); + } + + D_FREE(filter.weights); +} + -- cgit