diff --git a/.gitmodules b/.gitmodules index 2dedfa5..a99d833 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "3p/libxbr-standalone"] - path = 3p/libxbr-standalone - url = https://github.com/Treeki/libxbr-standalone.git - ignore = dirty [submodule "3p/vcpkg"] path = 3p/vcpkg url = https://github.com/microsoft/vcpkg.git diff --git a/3p/libxbr-standalone b/3p/libxbr-standalone deleted file mode 160000 index 3835e97..0000000 --- a/3p/libxbr-standalone +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3835e97d2f991b867a9764fa6ace730d25e4a19e diff --git a/CMakeLists.txt b/CMakeLists.txt index add0050..c0b5262 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ include_directories( ${SDL2_INCLUDE_DIRS} ) -file(GLOB SRC *.cpp 3p/inih/ini.c 3p/libxbr-standalone/xbr.c) +file(GLOB SRC *.cpp) list(FILTER SRC EXCLUDE REGEX ".*android.cpp|system_psp.cpp|system_wii.cpp") add_executable(${CMAKE_PROJECT_NAME} ${SRC} diff --git a/Makefile b/Makefile index 3c3ba0a..cf08144 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,8 @@ SRCS = andy.cpp benchmark.cpp fileio.cpp fs_posix.cpp game.cpp \ SCALERS := scaler_nearest.cpp scaler_xbr.cpp -OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o) 3p/libxbr-standalone/xbr.o -DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d) 3p/libxbr-standalone/xbr.d +OBJS = $(SRCS:.cpp=.o) $(SCALERS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) $(SCALERS:.cpp=.d) all: hode diff --git a/scaler.h b/scaler.h index aa3ed69..a917e66 100644 --- a/scaler.h +++ b/scaler.h @@ -8,12 +8,14 @@ #include "intern.h" -typedef void (*ScaleProc32)(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h); +typedef void (*PaletteProc)(const uint32_t *palette); +typedef void (*ScaleProc)(uint32_t *dst, int dstPitch, const uint8_t *src, int srcPitch, int w, int h, const uint32_t *palette); struct Scaler { const char *name; int factorMin, factorMax; - ScaleProc32 scale; + PaletteProc palette; + ScaleProc scale[3]; }; extern const Scaler scaler_nearest; diff --git a/scaler_nearest.cpp b/scaler_nearest.cpp index e595775..923d71a 100644 --- a/scaler_nearest.cpp +++ b/scaler_nearest.cpp @@ -1,46 +1,26 @@ #include "scaler.h" -static void scale_nearest(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { - switch (factor) { - case 2: - while (h--) { - uint32_t *p = dst; - for (int i = 0; i < w; ++i, p += 2) { - uint32_t c = *(src + i); - *(p) = c; - *(p + 1) = c; - *(p + dstPitch) = c; - *(p + dstPitch + 1) = c; +template +static void scale_nearest(uint32_t *dst, int dstPitch, const uint8_t *src, int srcPitch, int w, int h, const uint32_t *palette) { + while (h--) { + uint32_t *p = dst; + for (int i = 0; i < w; ++i, p += N) { + const uint32_t c = palette[src[i]]; + for (int j = 0; j < N; ++j) { + for (int k = 0; k < N; ++k) { + *(p + j * dstPitch + k) = c; + } } - dst += dstPitch * 2; - src += srcPitch; } - break; - case 3: - while (h--) { - uint32_t *p = dst; - for (int i = 0; i < w; ++i, p += 3) { - uint32_t c = *(src + i); - *(p) = c; - *(p + 1) = c; - *(p + 2) = c; - *(p + dstPitch) = c; - *(p + dstPitch + 1) = c; - *(p + dstPitch + 2) = c; - *(p + 2 * dstPitch) = c; - *(p + 2 * dstPitch + 1) = c; - *(p + 2 * dstPitch + 2) = c; - } - dst += dstPitch * 3; - src += srcPitch; - } - break; + dst += dstPitch * N; + src += srcPitch; } } const Scaler scaler_nearest = { "nearest", - 2, 3, - scale_nearest + 2, 4, + 0, + { scale_nearest<2>, scale_nearest<3>, scale_nearest<4> } }; diff --git a/scaler_xbr.cpp b/scaler_xbr.cpp index a90c546..f87a5c3 100644 --- a/scaler_xbr.cpp +++ b/scaler_xbr.cpp @@ -1,40 +1,269 @@ +// https://forums.libretro.com/t/xbr-algorithm-tutorial/123 +// https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavfilter/vf_xbr.c + #include "scaler.h" -extern "C" { -#include "3p/libxbr-standalone/filters.h" + +static uint8_t _yuv[256 * 3]; + +static int diffYuv(int x, int y) { + const int dy = _yuv[x * 3] - _yuv[y * 3]; + const int du = _yuv[x * 3 + 1] - _yuv[y * 3 + 1]; + const int dv = _yuv[x * 3 + 2] - _yuv[y * 3 + 2]; + return ABS(dy) + ABS(du) + ABS(dv); +} + +template +static uint32_t interpolate(uint32_t a, uint32_t b) { + static const uint32_t kMask = 0xFF00FF; + + const uint32_t m1 = (((((b & kMask) - (a & kMask)) * M) >> S) + (a & kMask)) & kMask; + a >>= 8; + b >>= 8; + const uint32_t m2 = (((((b & kMask) - (a & kMask)) * M) >> S) + (a & kMask)) & kMask; + return m1 | (m2 << 8); } -static bool _xbr_init; -static xbr_data _xbr_data; +#define COLOR(x) palette[x] + +#define ALPHA_BLEND_32_W(a, b) interpolate<1,3>(a, b) +#define ALPHA_BLEND_64_W(a, b) interpolate<1,2>(a, b) +#define ALPHA_BLEND_128_W(a, b) interpolate<1,1>(a, b) +#define ALPHA_BLEND_192_W(a, b) interpolate<3,2>(a, b) +#define ALPHA_BLEND_224_W(a, b) interpolate<7,3>(a, b) + +#define df(A, B) diffYuv(A, B) +#define eq(A, B) (df(A, B) < 155) + +#define filt2b(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3) do { \ + if (COLOR(PE) != COLOR(PH) && COLOR(PE) != COLOR(PF)) { \ + const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \ + const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \ + if (e <= i) { \ + const unsigned px = df(PE,PF) <= df(PE,PH) ? COLOR(PF) : COLOR(PH); \ + if (e < i && ( (!eq(PF,PB) && !eq(PH,PD)) || (eq(PE,PI) && (!eq(PF,I4) && !eq(PH,I5))) || eq(PE,PG) || eq(PE,PC)) ) { \ + const unsigned ke = df(PF,PG); \ + const unsigned ki = df(PH,PC); \ + const bool left = ke<<1 <= ki && COLOR(PE) != COLOR(PG) && COLOR(PD) != COLOR(PG); \ + const bool up = ke >= ki<<1 && COLOR(PE) != COLOR(PC) && COLOR(PB) != COLOR(PC); \ + if (left && up) { \ + E[N3] = ALPHA_BLEND_224_W(E[N3], px); \ + E[N2] = ALPHA_BLEND_64_W( E[N2], px); \ + E[N1] = E[N2]; \ + } else if (left) { \ + E[N3] = ALPHA_BLEND_192_W(E[N3], px); \ + E[N2] = ALPHA_BLEND_64_W( E[N2], px); \ + } else if (up) { \ + E[N3] = ALPHA_BLEND_192_W(E[N3], px); \ + E[N1] = ALPHA_BLEND_64_W( E[N1], px); \ + } else { \ + E[N3] = ALPHA_BLEND_128_W(E[N3], px); \ + } \ + } else { \ + E[N3] = ALPHA_BLEND_128_W(E[N3], px); \ + } \ + } \ + } \ +} while (0) + +#define filt3a(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3, N4, N5, N6, N7, N8) do { \ + if (COLOR(PE) != COLOR(PH) && COLOR(PE) != COLOR(PF)) { \ + const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \ + const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \ + if (e <= i) { \ + const unsigned px = df(PE,PF) <= df(PE,PH) ? COLOR(PF) : COLOR(PH); \ + if (e < i && ( (!eq(PF,PB) && !eq(PF,PC)) || (!eq(PH,PD) && !eq(PH,PG)) || ((eq(PE,PI) && (!eq(PF,F4) && !eq(PF,I4))) || (!eq(PH,H5) && !eq(PH,I5))) || eq(PE,PG) || eq(PE,PC)) ) { \ + const unsigned ke = df(PF,PG); \ + const unsigned ki = df(PH,PC); \ + const bool left = ke<<1 <= ki && COLOR(PE) != COLOR(PG) && COLOR(PD) != COLOR(PG); \ + const bool up = ke >= ki<<1 && COLOR(PE) != COLOR(PC) && COLOR(PB) != COLOR(PC); \ + if (left && up) { \ + E[N7] = ALPHA_BLEND_192_W(E[N7], px); \ + E[N6] = ALPHA_BLEND_64_W( E[N6], px); \ + E[N5] = E[N7]; \ + E[N2] = E[N6]; \ + E[N8] = px; \ + } else if (left) { \ + E[N7] = ALPHA_BLEND_192_W(E[N7], px); \ + E[N5] = ALPHA_BLEND_64_W( E[N5], px); \ + E[N6] = ALPHA_BLEND_64_W( E[N6], px); \ + E[N8] = px; \ + } else if (up) { \ + E[N5] = ALPHA_BLEND_192_W(E[N5], px); \ + E[N7] = ALPHA_BLEND_64_W( E[N7], px); \ + E[N2] = ALPHA_BLEND_64_W( E[N2], px); \ + E[N8] = px; \ + } else { \ + E[N8] = ALPHA_BLEND_224_W(E[N8], px); \ + E[N5] = ALPHA_BLEND_32_W( E[N5], px); \ + E[N7] = ALPHA_BLEND_32_W( E[N7], px); \ + } \ + } else { \ + E[N8] = ALPHA_BLEND_128_W(E[N8], px); \ + } \ + } \ + } \ +} while (0) + +#define filt4b(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N15, N14, N11, N3, N7, N10, N13, N12, N9, N6, N2, N1, N5, N8, N4, N0) do { \ + if (COLOR(PE) != COLOR(PH) && COLOR(PE) != COLOR(PF)) { \ + const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \ + const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \ + if (e <= i) { \ + const unsigned px = df(PE,PF) <= df(PE,PH) ? COLOR(PF) : COLOR(PH); \ + if (e < i && ( (!eq(PF,PB) && !eq(PH,PD)) || (eq(PE,PI) && (!eq(PF,I4) && !eq(PH,I5))) || eq(PE,PG) || eq(PE,PC)) ) { \ + const unsigned ke = df(PF,PG); \ + const unsigned ki = df(PH,PC); \ + const bool left = ke<<1 <= ki && COLOR(PE) != COLOR(PG) && COLOR(PD) != COLOR(PG); \ + const bool up = ke >= ki<<1 && COLOR(PE) != COLOR(PC) && COLOR(PB) != COLOR(PC); \ + if (left && up) { \ + E[N13] = ALPHA_BLEND_192_W(E[N13], px); \ + E[N12] = ALPHA_BLEND_64_W( E[N12], px); \ + E[N15] = E[N14] = E[N11] = px; \ + E[N10] = E[N3] = E[N12]; \ + E[N7] = E[N13]; \ + } else if (left) { \ + E[N11] = ALPHA_BLEND_192_W(E[N11], px); \ + E[N13] = ALPHA_BLEND_192_W(E[N13], px); \ + E[N10] = ALPHA_BLEND_64_W( E[N10], px); \ + E[N12] = ALPHA_BLEND_64_W( E[N12], px); \ + E[N14] = px; \ + E[N15] = px; \ + } else if (up) { \ + E[N14] = ALPHA_BLEND_192_W(E[N14], px); \ + E[N7 ] = ALPHA_BLEND_192_W(E[N7 ], px); \ + E[N10] = ALPHA_BLEND_64_W( E[N10], px); \ + E[N3 ] = ALPHA_BLEND_64_W( E[N3 ], px); \ + E[N11] = px; \ + E[N15] = px; \ + } else { \ + E[N11] = ALPHA_BLEND_128_W(E[N11], px); \ + E[N14] = ALPHA_BLEND_128_W(E[N14], px); \ + E[N15] = px; \ + } \ + } else { \ + E[N15] = ALPHA_BLEND_128_W(E[N15], px); \ + } \ + } \ + } \ +} while (0) + +template +static void scale_xbr(uint32_t *dst, int dstPitch, const uint8_t *src, int srcPitch, int w, int h, const uint32_t *palette) { + const int nl = dstPitch; + const int nl1 = dstPitch * 2; + const int nl2 = dstPitch * 3; + + for (int y = 0; y < h; ++y) { + + uint32_t *E = dst + y * dstPitch * N; + + const uint8_t *sa2 = src + y * srcPitch - 2; + const uint8_t *sa1 = sa2 - srcPitch; + const uint8_t *sa0 = sa1 - srcPitch; + const uint8_t *sa3 = sa2 + srcPitch; + const uint8_t *sa4 = sa3 + srcPitch; -static void scale_xbr(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h) { - if (!_xbr_init) { - xbr_init_data(&_xbr_data); - _xbr_init = true; + if (y <= 1) { + sa0 = sa1; + if (y == 0) { + sa0 = sa1 = sa2; + } + } + if (y >= h - 2) { + sa4 = sa3; + if (y == h - 1) { + sa4 = sa3 = sa2; + } + } + + for (int x = 0; x < w; ++x) { + + // A1 B1 C1 + // A0 PA PB PC C4 + // D0 PD PE PF F4 + // G0 PG PH PI I4 + // G5 H5 I5 + + const uint32_t B1 = sa0[2]; + const uint32_t PB = sa1[2]; + const uint32_t PE = sa2[2]; + const uint32_t PH = sa3[2]; + const uint32_t H5 = sa4[2]; + + const int pprev = 2 - (x > 0); + const uint32_t A1 = sa0[pprev]; + const uint32_t PA = sa1[pprev]; + const uint32_t PD = sa2[pprev]; + const uint32_t PG = sa3[pprev]; + const uint32_t G5 = sa4[pprev]; + + const int pprev2 = pprev - (x > 1); + const uint32_t A0 = sa1[pprev2]; + const uint32_t D0 = sa2[pprev2]; + const uint32_t G0 = sa3[pprev2]; + + const int pnext = 3 - (x == w - 1); + const uint32_t C1 = sa0[pnext]; + const uint32_t PC = sa1[pnext]; + const uint32_t PF = sa2[pnext]; + const uint32_t PI = sa3[pnext]; + const uint32_t I5 = sa4[pnext]; + + const int pnext2 = pnext + 1 - (x >= w - 2); + const uint32_t C4 = sa1[pnext2]; + const uint32_t F4 = sa2[pnext2]; + const uint32_t I4 = sa3[pnext2]; + + for (int j = 0; j < N; ++j) { + for (int i = 0; i < N; ++i) { + *(E + j * dstPitch + i) = COLOR(PE); + } + } + + + if (N == 2) { + filt2b(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, nl, nl+1); + filt2b(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl, 0, nl+1, 1); + filt2b(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl+1, nl, 1, 0); + filt2b(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 1, nl+1, 0, nl); + } else if (N == 3) { + filt3a(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, 2, nl, nl+1, nl+2, nl1, nl1+1, nl1+2); + filt3a(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl1, nl, 0, nl1+1, nl+1, 1, nl1+2, nl+2, 2); + filt3a(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl1+2, nl1+1, nl1, nl+2, nl+1, nl, 2, 1, 0); + filt3a(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 2, nl+2, nl1+2, 1, nl+1, nl1+1, 0, nl, nl1); + } else if (N == 4) { + filt4b(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, nl2+3, nl2+2, nl1+3, 3, nl+3, nl1+2, nl2+1, nl2, nl1+1, nl+2, 2, 1, nl+1, nl1, nl, 0); + filt4b(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, 3, nl+3, 2, 0, 1, nl+2, nl1+3, nl2+3, nl1+2, nl+1, nl, nl1, nl1+1, nl2+2, nl2+1, nl2); + filt4b(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, 0, 1, nl, nl2, nl1, nl+1, 2, 3, nl+2, nl1+1, nl2+1, nl2+2, nl1+2, nl+3, nl1+3, nl2+3); + filt4b(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, nl2, nl1, nl2+1, nl2+3, nl2+2, nl1+1, nl, 0, nl+1, nl1+2, nl1+3, nl+3, nl+2, 1, 2, 3); + } + + ++sa0; + ++sa1; + ++sa2; + ++sa3; + ++sa4; + + E += N; + } } - xbr_params params; - params.input = (uint8_t *)src; - params.output = (uint8_t *)dst; - params.inWidth = w; - params.inHeight = h; - params.inPitch = srcPitch * sizeof(uint32_t); - params.outPitch = dstPitch * sizeof(uint32_t); - params.data = &_xbr_data; - switch (factor) { - case 2: - xbr_filter_xbr2x(¶ms); - break; - case 3: - xbr_filter_xbr3x(¶ms); - break; - case 4: - xbr_filter_xbr4x(¶ms); - break; +} + +static void palette_xbr(const uint32_t *palette) { + for (int i = 0; i < 256; ++i) { + const int r = (palette[i] >> 16) & 255; + const int g = (palette[i] >> 8) & 255; + const int b = palette[i] & 255; + _yuv[i * 3] = ( 299 * r + 587 * g + 114 * b) / 1000; + _yuv[i * 3 + 1] = (-169 * r - 331 * g + 500 * b) / 1000 + 128; + _yuv[i * 3 + 2] = ( 500 * r - 419 * g - 81 * b) / 1000 + 128; } } const Scaler scaler_xbr = { "xbr", 2, 4, - scale_xbr + palette_xbr, + { scale_xbr<2>, scale_xbr<3>, scale_xbr<4> } }; diff --git a/system_sdl2.cpp b/system_sdl2.cpp index 0239263..4838ab2 100644 --- a/system_sdl2.cpp +++ b/system_sdl2.cpp @@ -41,7 +41,6 @@ struct System_SDL2 : System { }; uint8_t *_offscreenLut; - uint32_t *_offscreenRgb; SDL_Window *_window; SDL_Renderer *_renderer; SDL_Texture *_texture; @@ -111,7 +110,7 @@ bool System_hasCommandLine() { } System_SDL2::System_SDL2() : - _offscreenLut(0), _offscreenRgb(0), + _offscreenLut(0), _window(0), _renderer(0), _texture(0), _backgroundTexture(0), _fmt(0), _widescreenTexture(0), _controller(0), _joystick(0) { for (int i = 0; i < 256; ++i) { @@ -134,10 +133,6 @@ void System_SDL2::init(const char *title, int w, int h, bool fullscreen, bool wi if (!_offscreenLut) { error("System_SDL2::init() Unable to allocate offscreen buffer"); } - _offscreenRgb = (uint32_t *)malloc(offscreenSize * sizeof(uint32_t)); - if (!_offscreenRgb) { - error("System_SDL2::init() Unable to allocate RGB offscreen buffer"); - } memset(_offscreenLut, 0, offscreenSize); prepareScaledGfx(title, fullscreen, widescreen, yuv); @@ -166,8 +161,6 @@ void System_SDL2::init(const char *title, int w, int h, bool fullscreen, bool wi void System_SDL2::destroy() { free(_offscreenLut); _offscreenLut = 0; - free(_offscreenRgb); - _offscreenRgb = 0; if (_fmt) { SDL_FreeFormat(_fmt); @@ -274,6 +267,9 @@ void System_SDL2::copyRectWidescreen(int w, int h, const uint8_t *buf, const uin if (!_widescreenTexture) { return; } + if (_backgroundTexture) { + return; + } assert(w == _screenW && h == _screenH); void *ptr = 0; @@ -315,6 +311,11 @@ void System_SDL2::setScaler(const char *name, int multiplier) { break; } } + if (_scalerMultiplier < _scaler->factorMin) { + _scalerMultiplier = _scaler->factorMin; + } else if (_scalerMultiplier > _scaler->factorMax) { + _scalerMultiplier = _scaler->factorMax; + } } } @@ -333,9 +334,9 @@ void System_SDL2::setPalette(const uint8_t *pal, int n, int depth) { int g = pal[i * 3 + 1]; int b = pal[i * 3 + 2]; if (shift != 0) { - r = (r << shift) | (r >> depth); - g = (g << shift) | (g >> depth); - b = (b << shift) | (b >> depth); + r = (r << shift) | (r >> (depth - shift)); + g = (g << shift) | (g >> (depth - shift)); + b = (b << shift) | (b >> (depth - shift)); } r = _gammaLut[r]; g = _gammaLut[g]; @@ -345,6 +346,9 @@ void System_SDL2::setPalette(const uint8_t *pal, int n, int depth) { if (_backgroundTexture) { _pal[0] = 0; } + if (_scalerMultiplier != 1 && _scaler->palette) { + _scaler->palette(_pal); + } } void System_SDL2::clearPalette() { @@ -367,6 +371,11 @@ void System_SDL2::copyRect(int x, int y, int w, int h, const uint8_t *buf, int p void System_SDL2::copyYuv(int w, int h, const uint8_t *y, int ypitch, const uint8_t *u, int upitch, const uint8_t *v, int vpitch) { if (_backgroundTexture) { SDL_UpdateYUVTexture(_backgroundTexture, 0, y, ypitch, u, upitch, v, vpitch); + if (_widescreenTexture) { + SDL_SetRenderTarget(_renderer, _widescreenTexture); + SDL_RenderCopy(_renderer, _backgroundTexture, 0, 0); + SDL_SetRenderTarget(_renderer, 0); + } } } @@ -428,12 +437,12 @@ void System_SDL2::updateScreen(bool drawWidescreen) { src -= _shakeDx; } } - uint32_t *p = (_scalerMultiplier == 1) ? dst : _offscreenRgb; - for (int i = 0; i < w * h; ++i) { - p[i] = _pal[src[i]]; - } - if (_scalerMultiplier != 1) { - _scaler->scale(_scalerMultiplier, dst, dstPitch, _offscreenRgb, srcPitch, w, h); + if (_scalerMultiplier == 1) { + for (int i = 0; i < w * h; ++i) { + dst[i] = _pal[src[i]]; + } + } else { + (_scaler->scale[_scalerMultiplier - 2])(dst, dstPitch, src, w, w, h, _pal); } SDL_UnlockTexture(_texture); @@ -841,14 +850,18 @@ void System_SDL2::prepareScaledGfx(const char *caption, bool fullscreen, bool wi SDL_SetWindowIcon(_window, icon); SDL_FreeSurface(icon); } - _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED); + _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED | (yuv ? SDL_RENDERER_TARGETTEXTURE : 0)); SDL_RenderSetLogicalSize(_renderer, windowW, windowH); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, (_scaler == &scaler_nearest) ? "0" : "1"); const int pixelFormat = yuv ? SDL_PIXELFORMAT_RGBA8888 : SDL_PIXELFORMAT_RGB888; _texture = SDL_CreateTexture(_renderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, _texW, _texH); if (widescreen) { - _widescreenTexture = SDL_CreateTexture(_renderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, _screenW, _screenH); + if (yuv) { + _widescreenTexture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, 16, 16); + } else { + _widescreenTexture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, _screenW, _screenH); + } } else { _widescreenTexture = 0; }