From 24cb730f82bbe2b4873e8b59a214c2b1f27d10b3 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Sat, 26 Dec 2009 22:53:01 +0100 Subject: [PATCH] non-composited mode --- Makefile | 19 +- debian/rules | 5 +- platform/scaler.h | 36 +++ platform/sdlv.cpp | 534 +--------------------------------- platform/sdlv.h | 8 + platform/sdlvscalers.cpp | 727 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 794 insertions(+), 535 deletions(-) create mode 100644 platform/scaler.h create mode 100644 platform/sdlv.h create mode 100644 platform/sdlvscalers.cpp diff --git a/Makefile b/Makefile index ba45765..3a3e373 100644 --- a/Makefile +++ b/Makefile @@ -7,20 +7,23 @@ LDLIBS := -lz $(shell sdl-config --libs) $(shell pkg-config --libs x11) -lpopt # Sane defaults CONF_GUI?=1 +# Use Hildon Games Wrapper library CONF_HGW?=$(CONF_GUI) ifeq ($(ARCH),armel) CONF_BUILD_ASM_CPU?=1 CONF_BUILD_ASM_SPC700?=1 CONF_BUILD_ASM_SA1?=0 # Still not there - CONF_XSP?=1 CONF_BUILD_MISC_ROUTINES?=misc_armel else ifeq ($(ARCH),i386) CONF_BUILD_ASM_CPU?=0 CONF_BUILD_ASM_SPC700?=0 - CONF_BUILD_ASM_SA1?=0 # Still not there - CONF_XSP?=0 + CONF_BUILD_ASM_SA1?=0 CONF_BUILD_MISC_ROUTINES?=misc_i386 endif +# Hardware pixel doubling (in N8x0) +CONF_XSP?=0 +# Hildon Desktop compositing (in Fremantle) +CONF_HD?=0 # SNES stuff OBJS = apu.o c4.o c4emu.o cheats.o cheats2.o clip.o cpu.o cpuexec.o data.o @@ -46,10 +49,14 @@ else OBJS += sa1cpu.o endif + ifeq ($(CONF_XSP), 1) CPPFLAGS += -DCONF_XSP=1 $(shell pkg-config --cflags xsp) LDLIBS += $(shell pkg-config --libs xsp) endif +ifeq ($(CONF_HD), 1) + CPPFLAGS += -DCONF_HD=1 +endif OBJS += $(CONF_BUILD_MISC_ROUTINES).o @@ -60,6 +67,7 @@ OBJS += hacks.o # the glue code that sticks it all together in a monstruous way OBJS += platform/path.o platform/config.o OBJS += platform/sdl.o platform/sdlv.o platform/sdla.o platform/sdli.o +OBJS += platform/sdlvscalers.o ifeq ($(CONF_HGW), 1) CPPFLAGS += -DCONF_HGW=1 -I/usr/include/hgw @@ -110,5 +118,8 @@ clean: gui_clean install: gui_install endif -.PHONY: all clean remake deps install gui gui_clean +distclean: clean + rm -f config.mk + +.PHONY: all clean remake deps install gui gui_clean distclean diff --git a/debian/rules b/debian/rules index ea8e09c..31e3802 100755 --- a/debian/rules +++ b/debian/rules @@ -65,7 +65,10 @@ configure-stamp: echo CONF_HGW=1 >> config.mk ifeq ($(shell expr "$(MAEMO_VERSION)" ">" 4), 1) # Maemo 5 devices do not support Xsp - echo CONF_XSP=0 >> config.mk + # But they support hildon compositing stuff + echo CONF_HD=1 >> config.mk +else + echo CONF_XSP=1 >> config.mk endif echo ASFLAGS="$(ASFLAGS)" >> config.mk echo CFLAGS="$(CFLAGS)" >> config.mk diff --git a/platform/scaler.h b/platform/scaler.h new file mode 100644 index 0000000..601ca6c --- /dev/null +++ b/platform/scaler.h @@ -0,0 +1,36 @@ +#ifndef _PLATFORM_SCALER_H_ +#define _PLATFORM_SCALER_H_ + +class Scaler +{ +public: + Scaler() { }; + virtual ~Scaler() { }; + + virtual const char * getName() const = 0; + + virtual uint8* getDrawBuffer() const = 0; + virtual unsigned int getDrawBufferPitch() const = 0; + virtual void getRenderedGUIArea(unsigned short & x, unsigned short & y, + unsigned short & w, unsigned short & h) + const = 0; + virtual int getRatio() const = 0; + virtual void prepare() = 0; + virtual void finish() = 0; + virtual void pause() = 0; + virtual void resume() = 0; +}; + +class ScalerFactory +{ +public: + ScalerFactory() { }; + virtual ~ScalerFactory() { }; + virtual const char * getName() const = 0; + virtual bool canEnable(int bpp, int w, int h) const = 0; + virtual Scaler* instantiate(SDL_Surface* screen, int w, int h) const = 0; +}; + +const ScalerFactory* searchForScaler(int bpp, int w, int h); + +#endif diff --git a/platform/sdlv.cpp b/platform/sdlv.cpp index 573378c..1f35939 100644 --- a/platform/sdlv.cpp +++ b/platform/sdlv.cpp @@ -5,15 +5,13 @@ #include #include -#if CONF_XSP -# include -#endif - #include "snes9x.h" #include "platform.h" #include "display.h" #include "gfx.h" #include "ppu.h" +#include "sdlv.h" +#include "scaler.h" #define DIE(format, ...) do { \ fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \ @@ -23,538 +21,14 @@ struct gui GUI; -static SDL_Surface* screen; +SDL_Surface* screen; static SDL_Rect windowSize, screenSize; static bool gotWindowSize, gotScreenSize; -class Scaler; /** The current scaler object */ static Scaler* scaler; -static void centerRectangle(SDL_Rect& result, int areaW, int areaH, int w, int h) -{ - result.x = areaW / 2 - w / 2; - result.w = w; - result.y = areaH / 2 - h / 2; - result.h = h; -} - -class Scaler -{ -public: - Scaler() { }; - virtual ~Scaler() { }; - - virtual const char * getName() const = 0; - - virtual uint8* getDrawBuffer() const = 0; - virtual unsigned int getDrawBufferPitch() const = 0; - virtual void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) - const = 0; - virtual int getRatio() const = 0; - virtual void prepare() = 0; - virtual void finish() = 0; - virtual void pause() = 0; - virtual void resume() = 0; -}; - -class ScalerFactory -{ -public: - ScalerFactory() { }; - virtual ~ScalerFactory() { }; - virtual const char * getName() const = 0; - virtual bool canEnable(int bpp, int w, int h) const = 0; - virtual Scaler* instantiate(SDL_Surface* screen, int w, int h) const = 0; -}; - -class DummyScaler : public Scaler -{ - SDL_Surface * m_screen; - SDL_Rect m_area; - - DummyScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen) - { - centerRectangle(m_area, GUI.Width, GUI.Height, w, h); - } -public: - - ~DummyScaler() - { - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "none"; - } - - bool canEnable(int bpp, int w, int h) const - { - return true; - } - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new DummyScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "no scaling"; - } - - uint8* getDrawBuffer() const - { - const int Bpp = screen->format->BitsPerPixel / 8; - const int pitch = screen->pitch; - return ((uint8*) screen->pixels) - + (m_area.x * Bpp) - + (m_area.y * pitch); - }; - - unsigned int getDrawBufferPitch() const - { - return screen->pitch; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 1; - }; - - void prepare() { }; - - void finish() - { - SDL_UpdateRects(m_screen, 1, &m_area); - }; - - void pause() { }; - void resume() { }; -}; -const DummyScaler::Factory DummyScaler::factory; - -#ifdef __arm__ -class ARMScaler : public Scaler -{ - SDL_Surface * m_screen; - SDL_Rect m_area; - uint8 * m_surface; - const int m_w, m_h, m_Bpp; - - ARMScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen), m_w(w), m_h(h), - m_Bpp(m_screen->format->BitsPerPixel / 8) - { - centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2); - m_surface = reinterpret_cast(malloc(w * h * m_Bpp)); - } -public: - ~ARMScaler() - { - free(m_surface); - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "2x"; - } - - bool canEnable(int bpp, int w, int h) const - { - return bpp == 16 && w * 2 < GUI.Width && h * 2 < GUI.Height && - w % 16 == 0 /* asm assumes w div by 16 */; - } - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new ARMScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "software ARM 2x scaling"; - } - - uint8* getDrawBuffer() const - { - return m_surface; - }; - - unsigned int getDrawBufferPitch() const - { - return m_w * m_Bpp; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 2; - }; - - void prepare() { }; - - void finish() - { - uint16 * src = reinterpret_cast(m_surface); - uint16 * dst = reinterpret_cast( - ((uint8*) m_screen->pixels) - + (m_area.x * m_Bpp) - + (m_area.y * m_screen->pitch)); - const int src_pitch = m_w; - const int dst_pitch = m_screen->pitch / m_Bpp; - int y; - - for (y = 0; y < m_h*2; y++) { - asm volatile - ( - "mov r0, %0; mov r1, %1; mov r2, %2;" - "stmdb r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};" - "1: ldmia r1!,{r3,r4,r5,r6,r7,r8,r9,r10};" - "mov r14,r5,lsr #16;" - "mov r12,r5,lsl #16;" - "orr r14,r14,r14,lsl #16;" - "orr r12,r12,r12,lsr #16;" - "mov r11,r4,lsr #16;" - "mov r5,r4,lsl #16;" - "orr r11,r11,r11,lsl #16;" - "orr r5,r5,r5,lsr #16;" - "mov r4,r3,lsr #16;" - "mov r3,r3,lsl #16;" - "orr r4,r4,r4,lsl #16;" - "orr r3,r3,r3,lsr #16;" - "stmia r0!,{r3,r4,r5,r11,r12,r14};" - "mov r3,r6,lsl #16;" - "mov r4,r6,lsr #16;" - "orr r3,r3,r3,lsr #16;" - "orr r4,r4,r4,lsl #16;" - "mov r5,r7,lsl #16;" - "mov r6,r7,lsr #16;" - "orr r5,r5,r5,lsr #16;" - "orr r6,r6,r6,lsl #16;" - "mov r7,r8,lsl #16;" - "mov r8,r8,lsr #16;" - "orr r7,r7,r7,lsr #16;" - "orr r8,r8,r8,lsl #16;" - "mov r12,r10,lsr #16;" - "mov r11,r10,lsl #16;" - "orr r12,r12,r12,lsl #16;" - "orr r11,r11,r11,lsr #16;" - "mov r10,r9,lsr #16;" - "mov r9,r9,lsl #16;" - "orr r10,r10,r10,lsl #16;" - "orr r9,r9,r9,lsr #16;" - "stmia r0!,{r3,r4,r5,r6,r7,r8,r9,r10,r11,r12};" - "subs r2,r2,#16;" - "bhi 1b;" - "ldmia r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};" - : - : "r" (dst), "r" (src), "r" (m_w) - : "r0", "r1", "r2", "r3" - ); - dst += dst_pitch; - if (y&1) src += src_pitch; - } - - SDL_UpdateRects(m_screen, 1, &m_area); - }; - - void pause() { }; - void resume() { }; -}; -const ARMScaler::Factory ARMScaler::factory; -#endif - -class SWScaler : public Scaler -{ - SDL_Surface * m_screen; - SDL_Rect m_area; - uint8 * m_surface; - const int m_w, m_h, m_Bpp; - - SWScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen), m_w(w), m_h(h), - m_Bpp(m_screen->format->BitsPerPixel / 8) - { - centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2); - m_surface = reinterpret_cast(malloc(w * h * m_Bpp)); - } -public: - ~SWScaler() - { - free(m_surface); - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "soft2x"; - } - - bool canEnable(int bpp, int w, int h) const - { - return w * 2 < GUI.Width && h * 2 < GUI.Height; - } - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new SWScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "software 2x scaling"; - } - - uint8* getDrawBuffer() const - { - return m_surface; - }; - - unsigned int getDrawBufferPitch() const - { - return m_w * m_Bpp; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 2; - }; - - void prepare() { }; - - void finish() - { - uint16 * src = reinterpret_cast(m_surface); - uint16 * dst = reinterpret_cast( - ((uint8*) m_screen->pixels) - + (m_area.x * m_Bpp) - + (m_area.y * m_screen->pitch)); - const int src_pitch = m_w; - const int dst_pitch = m_screen->pitch / m_Bpp; - int x, y; - - for (y = 0; y < m_h*2; y++) { - for (x = 0; x < m_w*2; x+=2) { - dst[x] = src[x/2]; - dst[x + 1] = src[x/2]; - } - dst += dst_pitch; - if (y&1) src += src_pitch; - } - - SDL_UpdateRects(m_screen, 1, &m_area); - }; - - void pause() { }; - void resume() { }; -}; -const SWScaler::Factory SWScaler::factory; - -#if CONF_XSP -class XSPScaler : public Scaler -{ - SDL_Surface* m_screen; - SDL_Rect m_area; - SDL_Rect m_real_area; - bool m_should_enable, m_enabled; // Try to avoid flicker. - - static void setDoubling(bool enable) - { - SDL_SysWMinfo wminfo; - SDL_VERSION(&wminfo.version); - if ( SDL_GetWMInfo(&wminfo) ) { - Display *dpy = wminfo.info.x11.display; - XSPSetPixelDoubling(dpy, 0, enable ? 1 : 0); - XFlush(dpy); - } - } - - XSPScaler(SDL_Surface* screen, int w, int h) - : m_screen(screen), m_should_enable(true), m_enabled(false) - { - centerRectangle(m_area, GUI.Width, GUI.Height, - w * 2, h * 2); - - m_real_area.x = m_area.x; - m_real_area.y = m_area.y; - m_real_area.w = m_area.w / 2; - m_real_area.h = m_area.h / 2; - }; -public: - ~XSPScaler() - { - if (m_enabled) setDoubling(false); - }; - - class Factory : public ScalerFactory - { - const char * getName() const - { - return "xsp"; - } - - bool canEnable(int bpp, int w, int h) const - { - return w * 2 < GUI.Width && h * 2 < GUI.Height; - }; - - Scaler* instantiate(SDL_Surface* screen, int w, int h) const - { - return new XSPScaler(screen, w, h); - } - }; - - static const Factory factory; - - const char * getName() const - { - return "XSP pixel doubling"; - } - - uint8* getDrawBuffer() const - { - const int Bpp = screen->format->BitsPerPixel / 8; - const int pitch = screen->pitch; - return ((uint8*) screen->pixels) - + (m_area.x * Bpp) - + (m_area.y * pitch); - }; - - unsigned int getDrawBufferPitch() const - { - return screen->pitch; - }; - - void getRenderedGUIArea(unsigned short & x, unsigned short & y, - unsigned short & w, unsigned short & h) const - { - x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; - }; - - int getRatio() const - { - return 2; - }; - - void prepare() - { - if (m_should_enable && !m_enabled) { - setDoubling(true); - m_enabled = true; - } - }; - - void finish() - { - SDL_UpdateRects(m_screen, 1, &m_real_area); - }; - - void pause() - { - m_should_enable = false; - if (m_enabled) { - setDoubling(false); - m_enabled = false; - } - }; - - void resume() - { - m_should_enable = true; // Will enable later - }; -}; -const XSPScaler::Factory XSPScaler::factory; -#endif - -static const ScalerFactory* scalers[] = { -#if CONF_XSP - &XSPScaler::factory, -#endif -#ifdef __arm__ - &ARMScaler::factory, -#endif - &SWScaler::factory, - &DummyScaler::factory -}; - -static const ScalerFactory* searchForScaler(int bpp, int w, int h) -{ - const int n = sizeof(scalers) / sizeof(ScalerFactory*); - int i; - - if (Config.scaler && strcasecmp(Config.scaler, "help") == 0 ) { - // List scalers - printf("Scalers list:\n"); - for (i = 0; i < n; i++) { - printf(" %s\n", scalers[i]->getName()); - } - DIE("End of scalers list"); - } else if (Config.scaler && strcasecmp(Config.scaler, "auto") != 0 ) { - // We prefer a specific scaler - for (i = 0; i < n; i++) { - if (strcasecmp(scalers[i]->getName(), Config.scaler) == 0) { - if (scalers[i]->canEnable(bpp, w, h)) { - // Found the scaler selected by the user, and we can use it. - return scalers[i]; - } else { - fprintf(stderr, - "Selected scaler '%s' cannot be enabled in this mode\n", - Config.scaler); - break; // Fallback to another scaler. - } - } - } - if (i == n) { - fprintf(stderr, "Selected scaler '%s' does not exist\n", - Config.scaler); - } - } - - // Just try them all now, in a buildtime set priority. - for (i = 0; i < n; i++) { - if (scalers[i]->canEnable(bpp, w, h)) { - return scalers[i]; - } - } - - DIE("Can't use any scaler; this shouldn't happen."); -} - static void calculateScreenSize() { SDL_SysWMinfo wminfo; @@ -714,8 +188,8 @@ void S9xDeinitDisplay() void S9xVideoToggleFullscreen() { - Config.fullscreen = !Config.fullscreen; freeVideoSurface(); + Config.fullscreen = !Config.fullscreen; setupVideoSurface(); drawOnscreenControls(); } diff --git a/platform/sdlv.h b/platform/sdlv.h new file mode 100644 index 0000000..b713ea0 --- /dev/null +++ b/platform/sdlv.h @@ -0,0 +1,8 @@ +#ifndef _PLATFORM_SDLV_H_ +#define _PLATFORM_SDLV_H_ + +#include + +extern SDL_Surface* screen; + +#endif diff --git a/platform/sdlvscalers.cpp b/platform/sdlvscalers.cpp new file mode 100644 index 0000000..2839a7e --- /dev/null +++ b/platform/sdlvscalers.cpp @@ -0,0 +1,727 @@ +#include + +#include +#include +#include +#include + +#if CONF_XSP || CONF_HD +# include +#endif + +#include "snes9x.h" +#include "display.h" +#include "platform.h" +#include "scaler.h" +#include "sdlv.h" + +#define DIE(format, ...) do { \ + fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \ + fprintf(stderr, format "\n", ## __VA_ARGS__); \ + abort(); \ + } while (0); + +/* Helper functions */ + +static void centerRectangle(SDL_Rect& result, int areaW, int areaH, int w, int h) +{ + result.x = areaW / 2 - w / 2; + result.w = w; + result.y = areaH / 2 - h / 2; + result.h = h; +} + +/* Base scaler for stupid scalers */ +/** Does nothing but center the image */ +class DummyScaler : public Scaler +{ + SDL_Surface * m_screen; + SDL_Rect m_area; + +protected: + DummyScaler(SDL_Surface* screen, int w, int h) + : m_screen(screen) + { + centerRectangle(m_area, GUI.Width, GUI.Height, w, h); + } + +public: + + ~DummyScaler() + { + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "none"; + } + + bool canEnable(int bpp, int w, int h) const + { + return true; + } + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new DummyScaler(screen, w, h); + } + }; + + static const Factory factory; + + virtual const char * getName() const + { + return "no scaling"; + } + + virtual uint8* getDrawBuffer() const + { + const int Bpp = screen->format->BitsPerPixel / 8; + const int pitch = screen->pitch; + return ((uint8*) screen->pixels) + + (m_area.x * Bpp) + + (m_area.y * pitch); + }; + + virtual unsigned int getDrawBufferPitch() const + { + return screen->pitch; + }; + + virtual void getRenderedGUIArea(unsigned short & x, unsigned short & y, + unsigned short & w, unsigned short & h) const + { + x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; + }; + + virtual int getRatio() const + { + return 1; + }; + + virtual void prepare() { }; + + virtual void finish() + { + SDL_UpdateRects(m_screen, 1, &m_area); + }; + + virtual void pause() { }; + virtual void resume() { }; +}; +const DummyScaler::Factory DummyScaler::factory; + +/* Basic and slow software scaler */ + +class SWScaler : public Scaler +{ + SDL_Surface * m_screen; + SDL_Rect m_area; + uint8 * m_surface; + const int m_w, m_h, m_Bpp; + +protected: + SWScaler(SDL_Surface* screen, int w, int h) + : m_screen(screen), m_w(w), m_h(h), + m_Bpp(m_screen->format->BitsPerPixel / 8) + { + centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2); + m_surface = reinterpret_cast(malloc(w * h * m_Bpp)); + } +public: + ~SWScaler() + { + free(m_surface); + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "soft2x"; + } + + bool canEnable(int bpp, int w, int h) const + { + return w * 2 < GUI.Width && h * 2 < GUI.Height; + } + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new SWScaler(screen, w, h); + } + }; + + static const Factory factory; + + const char * getName() const + { + return "software 2x scaling"; + } + + uint8* getDrawBuffer() const + { + return m_surface; + }; + + unsigned int getDrawBufferPitch() const + { + return m_w * m_Bpp; + }; + + void getRenderedGUIArea(unsigned short & x, unsigned short & y, + unsigned short & w, unsigned short & h) const + { + x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; + }; + + int getRatio() const + { + return 2; + }; + + void prepare() { }; + + void finish() + { + uint16 * src = reinterpret_cast(m_surface); + uint16 * dst = reinterpret_cast( + ((uint8*) m_screen->pixels) + + (m_area.x * m_Bpp) + + (m_area.y * m_screen->pitch)); + const int src_pitch = m_w; + const int dst_pitch = m_screen->pitch / m_Bpp; + int x, y; + + for (y = 0; y < m_h*2; y++) { + for (x = 0; x < m_w*2; x+=2) { + dst[x] = src[x/2]; + dst[x + 1] = src[x/2]; + } + dst += dst_pitch; + if (y&1) src += src_pitch; + } + + SDL_UpdateRects(m_screen, 1, &m_area); + }; + + void pause() { }; + void resume() { }; +}; +const SWScaler::Factory SWScaler::factory; + +/* Platform specific scalers */ + +#ifdef __arm__ +class ARMScaler : public Scaler +{ + SDL_Surface * m_screen; + SDL_Rect m_area; + uint8 * m_surface; + const int m_w, m_h, m_Bpp; + + ARMScaler(SDL_Surface* screen, int w, int h) + : m_screen(screen), m_w(w), m_h(h), + m_Bpp(m_screen->format->BitsPerPixel / 8) + { + centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2); + m_surface = reinterpret_cast(malloc(w * h * m_Bpp)); + } +public: + ~ARMScaler() + { + free(m_surface); + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "arm2x"; + } + + bool canEnable(int bpp, int w, int h) const + { + return bpp == 16 && w * 2 < GUI.Width && h * 2 < GUI.Height && + w % 16 == 0 /* asm assumes w div by 16 */; + } + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new ARMScaler(screen, w, h); + } + }; + + static const Factory factory; + + const char * getName() const + { + return "software ARM 2x scaling"; + } + + uint8* getDrawBuffer() const + { + return m_surface; + }; + + unsigned int getDrawBufferPitch() const + { + return m_w * m_Bpp; + }; + + void getRenderedGUIArea(unsigned short & x, unsigned short & y, + unsigned short & w, unsigned short & h) const + { + x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; + }; + + int getRatio() const + { + return 2; + }; + + void prepare() { }; + + void finish() + { + uint16 * src = reinterpret_cast(m_surface); + uint16 * dst = reinterpret_cast( + ((uint8*) m_screen->pixels) + + (m_area.x * m_Bpp) + + (m_area.y * m_screen->pitch)); + const int src_pitch = m_w; + const int dst_pitch = m_screen->pitch / m_Bpp; + int y; + + for (y = 0; y < m_h*2; y++) { + asm volatile + ( + "mov r0, %0; mov r1, %1; mov r2, %2;" + "stmdb r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};" + "1: ldmia r1!,{r3,r4,r5,r6,r7,r8,r9,r10};" + "mov r14,r5,lsr #16;" + "mov r12,r5,lsl #16;" + "orr r14,r14,r14,lsl #16;" + "orr r12,r12,r12,lsr #16;" + "mov r11,r4,lsr #16;" + "mov r5,r4,lsl #16;" + "orr r11,r11,r11,lsl #16;" + "orr r5,r5,r5,lsr #16;" + "mov r4,r3,lsr #16;" + "mov r3,r3,lsl #16;" + "orr r4,r4,r4,lsl #16;" + "orr r3,r3,r3,lsr #16;" + "stmia r0!,{r3,r4,r5,r11,r12,r14};" + "mov r3,r6,lsl #16;" + "mov r4,r6,lsr #16;" + "orr r3,r3,r3,lsr #16;" + "orr r4,r4,r4,lsl #16;" + "mov r5,r7,lsl #16;" + "mov r6,r7,lsr #16;" + "orr r5,r5,r5,lsr #16;" + "orr r6,r6,r6,lsl #16;" + "mov r7,r8,lsl #16;" + "mov r8,r8,lsr #16;" + "orr r7,r7,r7,lsr #16;" + "orr r8,r8,r8,lsl #16;" + "mov r12,r10,lsr #16;" + "mov r11,r10,lsl #16;" + "orr r12,r12,r12,lsl #16;" + "orr r11,r11,r11,lsr #16;" + "mov r10,r9,lsr #16;" + "mov r9,r9,lsl #16;" + "orr r10,r10,r10,lsl #16;" + "orr r9,r9,r9,lsr #16;" + "stmia r0!,{r3,r4,r5,r6,r7,r8,r9,r10,r11,r12};" + "subs r2,r2,#16;" + "bhi 1b;" + "ldmia r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};" + : + : "r" (dst), "r" (src), "r" (m_w) + : "r0", "r1", "r2", "r3" + ); + dst += dst_pitch; + if (y&1) src += src_pitch; + } + + SDL_UpdateRects(m_screen, 1, &m_area); + }; + + void pause() { }; + void resume() { }; +}; +const ARMScaler::Factory ARMScaler::factory; +#endif + +#if CONF_HD + +enum hdAtoms { + ATOM_HILDON_NON_COMPOSITED_WINDOW = 0, + ATOM_NET_WM_STATE, + ATOM_NET_WM_STATE_FULLSCREEN, + ATOM_NET_WM_WINDOW_TYPE, + ATOM_NET_WM_WINDOW_TYPE_NORMAL, + ATOM_NET_WM_WINDOW_TYPE_DIALOG, + ATOM_HILDON_WM_WINDOW_TYPE_ANIMATION_ACTOR, + ATOM_HILDON_ANIMATION_CLIENT_READY, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_SHOW, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_POSITION, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_ROTATION, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_SCALE, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_ANCHOR, + ATOM_HILDON_ANIMATION_CLIENT_MESSAGE_PARENT, + ATOM_COUNT +}; + +static const char * hdAtomNames[] = { + "_HILDON_NON_COMPOSITED_WINDOW", + "_NET_WM_STATE", + "_NET_WM_STATE_FULLSCREEN", + "_NET_WM_WINDOW_TYPE", + "_NET_WM_WINDOW_TYPE_NORMAL", + "_NET_WM_WINDOW_TYPE_DIALOG", + "_HILDON_WM_WINDOW_TYPE_ANIMATION_ACTOR", + "_HILDON_ANIMATION_CLIENT_READY", + "_HILDON_ANIMATION_CLIENT_MESSAGE_SHOW", + "_HILDON_ANIMATION_CLIENT_MESSAGE_POSITION", + "_HILDON_ANIMATION_CLIENT_MESSAGE_ROTATION", + "_HILDON_ANIMATION_CLIENT_MESSAGE_SCALE", + "_HILDON_ANIMATION_CLIENT_MESSAGE_ANCHOR", + "_HILDON_ANIMATION_CLIENT_MESSAGE_PARENT", + "" +}; + +static Atom hdAtomsValues[ATOM_COUNT]; +static bool hdAtomsLoaded = false; + +#define HDATOM(X) hdAtomsValues[ ATOM ## X ] + +static void hildon_load_atoms(Display* display) +{ + if (hdAtomsLoaded) return; + + XInternAtoms(display, (char**)hdAtomNames, ATOM_COUNT, True, hdAtomsValues); + hdAtomsLoaded = true; + + if (HDATOM(_HILDON_NON_COMPOSITED_WINDOW) == None) { + DIE("Hildon Desktop seems not be loaded, since %s is not defined", + "_HILDON_NON_COMPOSITED_WINDOW"); + return; + } +} + +/** Enables or disables the Hildon NonCompositedWindow property */ +static void hildon_set_non_compositing(bool enable) +{ + SDL_SysWMinfo wminfo; + Display *display; + Window xwindow; + XSetWindowAttributes xattr; + Atom atom; + int one = 1; + + SDL_VERSION(&wminfo.version); + if (!SDL_GetWMInfo(&wminfo)) return; + + wminfo.info.x11.lock_func(); + display = wminfo.info.x11.display; + xwindow = wminfo.info.x11.fswindow; + hildon_load_atoms(display); + + if (enable) { + /* + * The basic idea behind this is to disable the override_redirect + * window attribute, which SDL sets, and instead use _NET_WM_STATE + * to tell hildon-desktop to fullscreen the app. + * I am not really happy with this, which should ideally be fixed + * at the libsdl level, but seems to work. + * As soon as the window is managed by Hildon-Desktop again, set for it + * not to be composited. + */ + XUnmapWindow(display, xwindow); + xattr.override_redirect = False; + XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &xattr); + + atom = HDATOM(_NET_WM_STATE_FULLSCREEN); + XChangeProperty(display, xwindow, HDATOM(_NET_WM_STATE), + XA_ATOM, 32, PropModeReplace, + (unsigned char *) &atom, 1); + + XChangeProperty(display, xwindow, HDATOM(_HILDON_NON_COMPOSITED_WINDOW), + XA_INTEGER, 32, PropModeReplace, + (unsigned char *) &one, 1); + XMapWindow(display, xwindow); + } else { + xattr.override_redirect = True; + XDeleteProperty(display, xwindow, + HDATOM(_HILDON_NON_COMPOSITED_WINDOW)); + XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &xattr); + } + + wminfo.info.x11.unlock_func(); +} + +class HDDummy : public DummyScaler +{ + HDDummy(SDL_Surface* screen, int w, int h) + : DummyScaler(screen, w, h) + { + hildon_set_non_compositing(true); + } + +public: + ~HDDummy() + { + hildon_set_non_compositing(false); + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "hddummy"; + } + + bool canEnable(int bpp, int w, int h) const + { + return true; + } + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new HDDummy(screen, w, h); + } + }; + + static const Factory factory; + + const char * getName() const + { + return "compositor disabled and no scaling"; + } +}; +const HDDummy::Factory HDDummy::factory; + +class HDSW : public SWScaler +{ + HDSW(SDL_Surface* screen, int w, int h) + : SWScaler(screen, w, h) + { + hildon_set_non_compositing(true); + } + +public: + ~HDSW() + { + hildon_set_non_compositing(false); + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "hdsoft2x"; + } + + bool canEnable(int bpp, int w, int h) const + { + return true; + } + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new HDSW(screen, w, h); + } + }; + + static const Factory factory; + + const char * getName() const + { + return "compositor disabled and software 2x scaling"; + } +}; +const HDSW::Factory HDSW::factory; +#endif + +#if CONF_XSP +class XSPScaler : public Scaler +{ + SDL_Surface* m_screen; + SDL_Rect m_area; + SDL_Rect m_real_area; + bool m_should_enable, m_enabled; // Try to avoid flicker. + + static void setDoubling(bool enable) + { + SDL_SysWMinfo wminfo; + SDL_VERSION(&wminfo.version); + if ( SDL_GetWMInfo(&wminfo) ) { + Display *dpy = wminfo.info.x11.display; + XSPSetPixelDoubling(dpy, 0, enable ? 1 : 0); + XFlush(dpy); + } + } + + XSPScaler(SDL_Surface* screen, int w, int h) + : m_screen(screen), m_should_enable(true), m_enabled(false) + { + centerRectangle(m_area, GUI.Width, GUI.Height, + w * 2, h * 2); + + m_real_area.x = m_area.x; + m_real_area.y = m_area.y; + m_real_area.w = m_area.w / 2; + m_real_area.h = m_area.h / 2; + }; +public: + ~XSPScaler() + { + if (m_enabled) setDoubling(false); + }; + + class Factory : public ScalerFactory + { + const char * getName() const + { + return "xsp"; + } + + bool canEnable(int bpp, int w, int h) const + { + return w * 2 < GUI.Width && h * 2 < GUI.Height; + }; + + Scaler* instantiate(SDL_Surface* screen, int w, int h) const + { + return new XSPScaler(screen, w, h); + } + }; + + static const Factory factory; + + const char * getName() const + { + return "XSP pixel doubling"; + } + + uint8* getDrawBuffer() const + { + const int Bpp = screen->format->BitsPerPixel / 8; + const int pitch = screen->pitch; + return ((uint8*) screen->pixels) + + (m_area.x * Bpp) + + (m_area.y * pitch); + }; + + unsigned int getDrawBufferPitch() const + { + return screen->pitch; + }; + + void getRenderedGUIArea(unsigned short & x, unsigned short & y, + unsigned short & w, unsigned short & h) const + { + x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h; + }; + + int getRatio() const + { + return 2; + }; + + void prepare() + { + if (m_should_enable && !m_enabled) { + setDoubling(true); + m_enabled = true; + } + }; + + void finish() + { + SDL_UpdateRects(m_screen, 1, &m_real_area); + }; + + void pause() + { + m_should_enable = false; + if (m_enabled) { + setDoubling(false); + m_enabled = false; + } + }; + + void resume() + { + m_should_enable = true; // Will enable later + }; +}; +const XSPScaler::Factory XSPScaler::factory; +#endif + +static const ScalerFactory* scalers[] = { +/* More useful scalers come first */ +#if CONF_XSP + &XSPScaler::factory, +#endif +#ifdef __arm__ + &ARMScaler::factory, +#endif +#if CONF_HD + &HDSW::factory, +#endif + &SWScaler::factory, +#if CONF_HD + &HDDummy::factory, +#endif + &DummyScaler::factory, +}; + +/* Entry point functions */ + +const ScalerFactory* searchForScaler(int bpp, int w, int h) +{ + const int n = sizeof(scalers) / sizeof(ScalerFactory*); + int i; + + if (Config.scaler && strcasecmp(Config.scaler, "help") == 0 ) { + // List scalers + printf("Scalers list:\n"); + for (i = 0; i < n; i++) { + printf(" %s\n", scalers[i]->getName()); + } + DIE("End of scalers list"); + } else if (Config.scaler && strcasecmp(Config.scaler, "auto") != 0 ) { + // We prefer a specific scaler + for (i = 0; i < n; i++) { + if (strcasecmp(scalers[i]->getName(), Config.scaler) == 0) { + if (scalers[i]->canEnable(bpp, w, h)) { + // Found the scaler selected by the user, and we can use it. + return scalers[i]; + } else { + fprintf(stderr, + "Selected scaler '%s' cannot be enabled in this mode\n", + Config.scaler); + break; // Fallback to another scaler. + } + } + } + if (i == n) { + fprintf(stderr, "Selected scaler '%s' does not exist\n", + Config.scaler); + } + } + + // Just try them all now, in a buildtime set priority. + for (i = 0; i < n; i++) { + if (scalers[i]->canEnable(bpp, w, h)) { + return scalers[i]; + } + } + + DIE("Can't use any scaler; this shouldn't happen."); +} + -- 1.7.9.5