From 7f6002caba3f0a6749820c2772161caf55b8d267 Mon Sep 17 00:00:00 2001 From: neonloop Date: Fri, 7 May 2021 20:00:12 +0000 Subject: Initial commit (uqm-0.8.0) --- src/libs/graphics/sdl/scalers.c | 289 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/libs/graphics/sdl/scalers.c (limited to 'src/libs/graphics/sdl/scalers.c') diff --git a/src/libs/graphics/sdl/scalers.c b/src/libs/graphics/sdl/scalers.c new file mode 100644 index 0000000..751dae3 --- /dev/null +++ b/src/libs/graphics/sdl/scalers.c @@ -0,0 +1,289 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "types.h" +#include "libs/graphics/sdl/sdl_common.h" +#include "libs/platform.h" +#include "libs/log.h" +#include "scalers.h" +#include "scaleint.h" +#include "2xscalers.h" +#ifdef USE_PLATFORM_ACCEL +# ifndef __APPLE__ + // MacOS X framework has no SDL_cpuinfo.h for some reason +# include SDL_INCLUDE(SDL_cpuinfo.h) +# endif +# ifdef MMX_ASM +# include "2xscalers_mmx.h" +# endif /* MMX_ASM */ +#endif /* USE_PLATFORM_ACCEL */ + +#if SDL_MAJOR_VERSION == 1 +#define SDL_HasMMX SDL_HasMMXExt +#endif + +typedef enum +{ + SCALEPLAT_NULL = PLATFORM_NULL, + SCALEPLAT_C = PLATFORM_C, + SCALEPLAT_MMX = PLATFORM_MMX, + SCALEPLAT_SSE = PLATFORM_SSE, + SCALEPLAT_3DNOW = PLATFORM_3DNOW, + SCALEPLAT_ALTIVEC = PLATFORM_ALTIVEC, + + SCALEPLAT_C_RGBA, + SCALEPLAT_C_BGRA, + SCALEPLAT_C_ARGB, + SCALEPLAT_C_ABGR, + +} Scale_PlatType_t; + + +// RGB -> YUV transformation +// the RGB vector is multiplied by the transformation matrix +// to get the YUV vector +#if 0 +// original table -- not used +const int YUV_matrix[3][3] = +{ + /* Y U V */ + /* R */ {0.2989, -0.1687, 0.5000}, + /* G */ {0.5867, -0.3312, -0.4183}, + /* B */ {0.1144, 0.5000, -0.0816} +}; +#else +// scaled up by a 2^14 factor, with Y doubled +const int YUV_matrix[3][3] = +{ + /* Y U V */ + /* R */ { 9794, -2764, 8192}, + /* G */ {19224, -5428, -6853}, + /* B */ { 3749, 8192, -1339} +}; +#endif + +// pre-computed transformations for 8 bits per channel +int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256]; +sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512]; + +// pre-computed transformations for RGB555 +YUV_VECTOR RGB15_to_YUV[0x8000]; + +PLATFORM_TYPE force_platform = PLATFORM_NULL; +Scale_PlatType_t Scale_Platform = SCALEPLAT_NULL; + + +// pre-compute the RGB->YUV transformations +void +Scale_Init (void) +{ + int i1, i2, i3; + + for (i1 = 0; i1 < 3; i1++) // enum R,G,B + for (i2 = 0; i2 < 3; i2++) // enum Y,U,V + for (i3 = 0; i3 < 256; i3++) // enum possible channel vals + { + RGB_to_YUV[i1][i2][i3] = + (YUV_matrix[i1][i2] * i3) >> 14; + } + + for (i1 = 0; i1 < 3; i1++) // enum R,G,B + for (i2 = 0; i2 < 3; i2++) // enum Y,U,V + for (i3 = -255; i3 < 256; i3++) // enum possible channel delta vals + { + dRGB_to_dYUV[i1][i2][i3 + 255] = + (YUV_matrix[i1][i2] * i3) >> 14; + } + + for (i1 = 0; i1 < 32; ++i1) + for (i2 = 0; i2 < 32; ++i2) + for (i3 = 0; i3 < 32; ++i3) + { + int y, u, v; + // adding upper bits halved for error correction + int r = (i1 << 3) | (i1 >> 3); + int g = (i2 << 3) | (i2 >> 3); + int b = (i3 << 3) | (i3 >> 3); + + y = ( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y] + + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y] + + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y] + ) >> 15; // we dont need Y doubled, need Y to fit 8 bits + + // U and V are half the importance of Y + u = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_U] + + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_U] + + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_U] + ) >> 15); // halved + + v = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_V] + + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_V] + + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_V] + ) >> 15); // halved + + RGB15_to_YUV[(i1 << 10) | (i2 << 5) | i3] = (y << 16) | (u << 8) | v; + } +} + + +// expands the given rectangle in all directions by 'expansion' +// guarded by 'limits' +void +Scale_ExpandRect (SDL_Rect* rect, int expansion, const SDL_Rect* limits) +{ + if (rect->x - expansion >= limits->x) + { + rect->w += expansion; + rect->x -= expansion; + } + else + { + rect->w += rect->x - limits->x; + rect->x = limits->x; + } + + if (rect->y - expansion >= limits->y) + { + rect->h += expansion; + rect->y -= expansion; + } + else + { + rect->h += rect->y - limits->y; + rect->y = limits->y; + } + + if (rect->x + rect->w + expansion <= limits->w) + rect->w += expansion; + else + rect->w = limits->w - rect->x; + + if (rect->y + rect->h + expansion <= limits->h) + rect->h += expansion; + else + rect->h = limits->h - rect->y; +} + + +// Platform+Scaler function lookups + +typedef struct +{ + Scale_PlatType_t platform; + const Scale_FuncDef_t* funcdefs; +} Scale_PlatDef_t; + + +static const Scale_PlatDef_t +Scale_PlatDefs[] = +{ +#if defined(MMX_ASM) + {SCALEPLAT_SSE, Scale_SSE_Functions}, + {SCALEPLAT_3DNOW, Scale_3DNow_Functions}, + {SCALEPLAT_MMX, Scale_MMX_Functions}, +#endif /* MMX_ASM */ + // Default + {SCALEPLAT_NULL, Scale_C_Functions} +}; + + +TFB_ScaleFunc +Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt) +{ + const Scale_PlatDef_t* pdef; + const Scale_FuncDef_t* fdef; + + (void)flags; + + Scale_Platform = SCALEPLAT_NULL; + + // first match wins + // add better platform techs to the top +#ifdef MMX_ASM + if ( (!force_platform && (SDL_HasSSE () || SDL_HasMMX ())) + || force_platform == PLATFORM_SSE) + { + log_add (log_Info, "Screen scalers are using SSE/MMX-Ext/MMX code"); + Scale_Platform = SCALEPLAT_SSE; + + Scale_SSE_PrepPlatform (fmt); + } + else + if ( (!force_platform && SDL_HasAltiVec ()) + || force_platform == PLATFORM_ALTIVEC) + { + log_add (log_Info, "Screen scalers would use AltiVec code " + "if someone actually wrote it"); + //Scale_Platform = SCALEPLAT_ALTIVEC; + } + else + if ( (!force_platform && SDL_Has3DNow ()) + || force_platform == PLATFORM_3DNOW) + { + log_add (log_Info, "Screen scalers are using 3DNow/MMX code"); + Scale_Platform = SCALEPLAT_3DNOW; + + Scale_3DNow_PrepPlatform (fmt); + } + else + if ( (!force_platform && SDL_HasMMX ()) + || force_platform == PLATFORM_MMX) + { + log_add (log_Info, "Screen scalers are using MMX code"); + Scale_Platform = SCALEPLAT_MMX; + + Scale_MMX_PrepPlatform (fmt); + } +#endif + + if (Scale_Platform == SCALEPLAT_NULL) + { // Plain C versions + if (fmt->Rmask == 0xff000000 && fmt->Bmask == 0x0000ff00) + Scale_Platform = SCALEPLAT_C_RGBA; + else if (fmt->Rmask == 0x00ff0000 && fmt->Bmask == 0x000000ff) + Scale_Platform = SCALEPLAT_C_ARGB; + else if (fmt->Rmask == 0x0000ff00 && fmt->Bmask == 0xff000000) + Scale_Platform = SCALEPLAT_C_BGRA; + else if (fmt->Rmask == 0x000000ff && fmt->Bmask == 0x00ff0000) + Scale_Platform = SCALEPLAT_C_ABGR; + else + { // use slowest default + log_add (log_Warning, "Scale_PrepPlatform(): unknown masks " + "(Red %08x, Blue %08x)", fmt->Rmask, fmt->Bmask); + Scale_Platform = SCALEPLAT_C; + } + + if (Scale_Platform == SCALEPLAT_C) + log_add (log_Info, "Screen scalers are using slow generic C code"); + else + log_add (log_Info, "Screen scalers are using optimized C code"); + } + + // Lookup the scaling function + // First find the right platform + for (pdef = Scale_PlatDefs; + pdef->platform != Scale_Platform && pdef->platform != SCALEPLAT_NULL; + ++pdef) + ; + // Next find the right function + for (fdef = pdef->funcdefs; + (flags & fdef->flag) != fdef->flag; + ++fdef) + ; + + return fdef->func; +} + -- cgit v1.2.3