Add 2xBR and DDT video filters (#1070)

* Add 2xBR and DDT video filters

* Add 2xBR and DDT video filters

* Add 2xBR and DDT video filters

* Add 2xBR and DDT video filters (fix file)
This commit is contained in:
Hyllian 2023-09-18 12:17:37 -03:00 committed by GitHub
parent 1e957ae1a9
commit 19c89b028e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 698 additions and 390 deletions

View File

@ -36,6 +36,8 @@ TFilterMethod FilterMethod;
template<int GuiScale> void RenderHQ2X (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
template<int GuiScale> void RenderScale2X (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
template<int GuiScale> void RenderTVMode (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
template<int GuiScale> void Render2xBR (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
template<int GuiScale> void RenderDDT (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height);
const char* GetFilterName (RenderFilter filterID)
{
@ -48,6 +50,8 @@ const char* GetFilterName (RenderFilter filterID)
case FILTER_HQ2XBOLD: return "hq2x Bold";
case FILTER_SCALE2X: return "Scale2x";
case FILTER_TVMODE: return "TV Mode";
case FILTER_2XBR: return "2xBR";
case FILTER_DDT: return "DDT";
}
}
@ -61,6 +65,8 @@ static TFilterMethod FilterToMethod (RenderFilter filterID)
case FILTER_HQ2XBOLD: return RenderHQ2X<FILTER_HQ2XBOLD>;
case FILTER_SCALE2X: return RenderScale2X<FILTER_SCALE2X>;
case FILTER_TVMODE: return RenderTVMode<FILTER_TVMODE>;
case FILTER_2XBR: return Render2xBR<FILTER_2XBR>;
case FILTER_DDT: return RenderDDT<FILTER_DDT>;
default: return 0;
}
}
@ -77,6 +83,8 @@ int GetFilterScale(RenderFilter filterID)
case FILTER_HQ2XBOLD:
case FILTER_SCALE2X:
case FILTER_TVMODE:
case FILTER_2XBR:
case FILTER_DDT:
return 2;
}
}
@ -549,3 +557,299 @@ void RenderTVMode (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitc
q += nextlineDst << 1;
}
}
//---------------------------------------------------------------------------------------------------------------------------
static int RGBlum[65536];
static const uint32 tbl_5_to_8[32]={0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255};
static const uint32 tbl_6_to_8[64]={0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255};
//---------------------------------------------------------------------------------------------------------------------------
#define RB_MASK565 0xF81F
#define R_MASK565 0xF800
#define G_MASK565 0x07E0
#define B_MASK565 0x001F
#define LB_MASK565 0xF7DE
static const uint16 rb_mask = RB_MASK565;
static const uint16 r_mask = R_MASK565;
static const uint16 g_mask = G_MASK565;
static const uint16 b_mask = B_MASK565;
static const uint16 lb_mask = LB_MASK565;
#define ALPHA_BLEND_128_W(dst, src) dst = ((src & lb_mask) >> 1) + ((dst & lb_mask) >> 1)
#define ALPHA_BLEND_16_W(dst, src) \
dst = ( (rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask))) >>4))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask))) >>4))) )
#define ALPHA_BLEND_32_W(dst, src) \
dst = ( \
(rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask))) >>3))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask))) >>3))) )
#define ALPHA_BLEND_64_W(dst, src) \
dst = ( \
(rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask))) >>2))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask))) >>2))) )
#define ALPHA_BLEND_192_W(dst, src) \
dst = ( \
(rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask)) * 192) >>8))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask)) * 192) >>8))) )
#define ALPHA_BLEND_224_W(dst, src) \
dst = ( \
(rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask)) * 224) >>8))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask)) * 224) >>8))) )
#define LEFT_UP_2_2X(N3, N2, N1, PIXEL)\
ALPHA_BLEND_224_W(Ep[N3], PIXEL); \
ALPHA_BLEND_64_W( Ep[N2], PIXEL); \
Ep[N1] = Ep[N2]; \
#define LEFT_2_2X(N3, N2, PIXEL)\
ALPHA_BLEND_192_W(Ep[N3], PIXEL); \
ALPHA_BLEND_64_W( Ep[N2], PIXEL); \
#define UP_2_2X(N3, N1, PIXEL)\
ALPHA_BLEND_192_W(Ep[N3], PIXEL); \
ALPHA_BLEND_64_W( Ep[N1], PIXEL); \
#define DIA_2X(N3, PIXEL)\
ALPHA_BLEND_128_W(Ep[N3], PIXEL); \
#define ALPHA_BLEND_X_W(dst, src, VAL) \
dst = ( \
(rb_mask & ((dst & rb_mask) + ((((src & rb_mask) - (dst & rb_mask)) * VAL) >>5))) | \
( g_mask & ((dst & g_mask) + ((((src & g_mask) - (dst & g_mask)) * VAL) >>5))))
#define BIL2X(PF, PH, PI, N3) \
ALPHA_BLEND_64_W(Ep[N3], PF); \
ALPHA_BLEND_X_W(Ep[N3], PH, 6); \
ALPHA_BLEND_16_W(Ep[N3], PI); \
#define DDT2X_BC(PF, PH, PI, N3) \
ALPHA_BLEND_64_W(Ep[N3], PI); \
#define DDT2X_D(PF, PH, N3) \
ALPHA_BLEND_X_W(Ep[N3], PF, 11); \
ALPHA_BLEND_64_W(Ep[N3], PH); \
#define df(A, B)\
abs(RGBlum[A] - RGBlum[B])\
#define eq(A, B)\
(df(A, B) < 155)\
#define XBR(PE, PI, PH, PF, PG, PC, PD, PB, PA, N0, N1, N2, N3) \
irlv1 = (PE!=PH && PE!=PF); \
if ( irlv1 )\
{\
wd1 = (df(PE,PC)+df(PE,PG))+(df(PH,PF)<<2); \
wd2 = (df(PH,PD)+df(PF,PB))+(df(PE,PI)<<2); \
if (wd1<wd2)\
{\
if ( ( !eq(PF,PB) && !eq(PF,PC) || !eq(PH,PD) && !eq(PH,PG) || eq(PE,PG) || eq(PE,PC)) )\
{\
dFG=df(PF,PG); dHC=df(PH,PC); \
irlv2u = (PE!=PC && PB!=PC); irlv2l = (PE!=PG && PD!=PG); px = (df(PE,PF) <= df(PE,PH)) ? PF : PH; \
if ( irlv2l && irlv2u && ((dFG<<1)<=dHC) && (dFG>=(dHC<<1)) ) \
{\
LEFT_UP_2_2X(N3, N2, N1, px)\
}\
else if ( irlv2l && ((dFG<<1)<=dHC) ) \
{\
LEFT_2_2X(N3, N2, px);\
}\
else if ( irlv2u && (dFG>=(dHC<<1)) ) \
{\
UP_2_2X(N3, N1, px);\
}\
else \
{\
DIA_2X(N3, px);\
}\
}\
}\
else if (wd1<=wd2)\
{\
px = (df(PE,PF) <= df(PE,PH)) ? PF : PH;\
ALPHA_BLEND_64_W( Ep[N3], px); \
}\
}\
#define BLEND_SUBPIXEL(PE, PI, PH, PF, PG, PC, PD, PB, PA, N0, N1, N2, N3) \
if (PE!=PF || PE!=PH || PE!=PI) \
{\
wd1 = (df(PH,PF)); \
wd2 = (df(PE,PI)); \
if (wd1>wd2)\
{\
DDT2X_BC(PF, PH, PI, N3);\
}\
else if (wd1<wd2)\
{\
DDT2X_D(PF, PH, N3);\
}\
else\
{\
BIL2X(PF, PH, PI, N3);\
}\
}
#define DDT(PE, PI, PH, PF, PG, PC, PD, PB, PA, N0, N1, N2, N3) \
if (PE!=PH || PE!=PI || PE!=PF || PE!=PC || PE!=PB || PE!=PA || PE!=PD || PE!=PG) \
{\
BLEND_SUBPIXEL(PE, PI, PH, PF, PG, PC, PD, PB, PA, N0, N1, N2, N3);\
BLEND_SUBPIXEL(PE, PC, PF, PB, PI, PA, PH, PD, PG, N2, N0, N3, N1);\
BLEND_SUBPIXEL(PE, PA, PB, PD, PC, PG, PF, PH, PI, N3, N2, N1, N0);\
BLEND_SUBPIXEL(PE, PG, PD, PH, PA, PI, PB, PF, PC, N1, N3, N0, N2);\
}\
//---------------------------------------------------------------------------------------------------------------------------
void SetupFormat(void)
{
uint32 c, r, g, b, y, u, v;
for (c = 0; c < 65536; c++)
{
r = tbl_5_to_8[(c & R_MASK565) >> 11];
g = tbl_6_to_8[(c & G_MASK565) >> 5];
b = tbl_5_to_8[(c & B_MASK565) ];
y = ((r<<4) + (g<<5) + (b<<2));
u = ( -r - (g<<1) + (b<<2));
v = ((r<<1) - (g<<1) - (b>>1));
RGBlum[c] = (int) (y + u + v);
}
}
template<int GuiScale>
void Render2xBR (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
// If Snes9x is rendering anything in HiRes, then just copy, don't interpolate
if (height > SNES_HEIGHT_EXTENDED || width == 512)
{
return;
}
uint32 wd1, wd2, px;
uint32 irlv1, irlv2u, irlv2l;
uint32 dFG, dHC;
uint32 E0, E1, E2, E3;
uint16 A, B, C, D, E, F, G, H, I;
uint32 nextlineSrc = srcPitch / sizeof(uint16);
uint16 *p = (uint16 *)srcPtr;
uint32 nextlineDst = dstPitch / sizeof(uint16);
uint16 *Ep = (uint16 *)dstPtr;
while (height--) {
A = *(p - 1 - nextlineSrc);
B = *(p - nextlineSrc);
D = *(p - 1);
E = *(p);
G = *(p - 1 + nextlineSrc);
H = *(p + nextlineSrc);
for (int i = 0; i < width; i++) {
C = *(p + i + 1 - nextlineSrc);
F = *(p + i + 1);
I = *(p + i + 1 + nextlineSrc);
E0 = (i << 1);
E1 = (i << 1) + 1;
E2 = (i << 1) + nextlineDst;
E3 = (i << 1) + nextlineDst + 1;
Ep[E0] = Ep[E1] = Ep[E2] = Ep[E3] = E; // 0, 1, 2, 3
XBR( E, I, H, F, G, C, D, B, A, E0, E1, E2, E3);
XBR( E, C, F, B, I, A, H, D, G, E2, E0, E3, E1);
XBR( E, A, B, D, C, G, F, H, I, E3, E2, E1, E0);
XBR( E, G, D, H, A, I, B, F, C, E1, E3, E0, E2);
A= B; B=C;
D= E; E=F;
G= H; H=I;
}
p += nextlineSrc;
Ep += nextlineDst << 1;
}
}
template<int GuiScale>
void RenderDDT (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
// If Snes9x is rendering anything in HiRes, then just copy, don't interpolate
if (height > SNES_HEIGHT_EXTENDED || width == 512)
{
return;
}
uint32 wd1, wd2, px;
uint32 irlv1, irlv2u, irlv2l;
uint32 dFG, dHC;
uint32 E0, E1, E2, E3;
uint16 A, B, C, D, E, F, G, H, I;
uint32 nextlineSrc = srcPitch / sizeof(uint16);
uint16 *p = (uint16 *)srcPtr;
uint32 nextlineDst = dstPitch / sizeof(uint16);
uint16 *Ep = (uint16 *)dstPtr;
while (height--) {
A = *(p - 1 - nextlineSrc);
B = *(p - nextlineSrc);
D = *(p - 1);
E = *(p);
G = *(p - 1 + nextlineSrc);
H = *(p + nextlineSrc);
for (int i = 0; i < width; i++) {
C = *(p + i + 1 - nextlineSrc);
F = *(p + i + 1);
I = *(p + i + 1 + nextlineSrc);
E0 = (i << 1);
E1 = (i << 1) + 1;
E2 = (i << 1) + nextlineDst;
E3 = (i << 1) + nextlineDst + 1;
Ep[E0] = Ep[E1] = Ep[E2] = Ep[E3] = E; // 0, 1, 2, 3
DDT( E, I, H, F, G, C, D, B, A, E0, E1, E2, E3);
A= B; B=C;
D= E; E=F;
G= H; H=I;
}
p += nextlineSrc;
Ep += nextlineDst << 1;
}
}

View File

@ -28,6 +28,8 @@ enum RenderFilter{
FILTER_HQ2XBOLD,
FILTER_SCALE2X,
FILTER_TVMODE,
FILTER_2XBR,
FILTER_DDT,
NUM_FILTERS
};
@ -50,6 +52,7 @@ void SelectFilterMethod ();
const char* GetFilterName (RenderFilter filterID);
int GetFilterScale(RenderFilter filterID);
void InitLUTs();
void SetupFormat();
#endif

View File

@ -568,6 +568,7 @@ if (CONF_GetAspectRatio() == CONF_ASPECT_16_9 && (*(u32*)(0xCD8005A0) >> 16) ==
SetupVideoMode(rmode);
#ifdef HW_RVL
InitLUTs(); // init LUTs for hq2x
SetupFormat(); // For 2xBR
#endif
LWP_CreateThread (&vbthread, vbgetback, NULL, vbstack, TSTACK, 68);