9 # include <SDL_syswm.h>
10 # include <X11/extensions/Xsp.h>
20 #define DIE(format, ...) do { \
21 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
22 fprintf(stderr, format "\n", ## __VA_ARGS__); \
26 /* Helper functions */
28 static void centerRectangle(SDL_Rect& result, int areaW, int areaH, int w, int h)
30 result.x = areaW / 2 - w / 2;
32 result.y = areaH / 2 - h / 2;
34 /* We need to keep this 4-byte aligned (each pixel is 2-byte) */
38 /* Base scaler for stupid scalers */
39 /** Does nothing but center the image */
40 class DummyScaler : public Scaler
42 SDL_Surface * m_screen;
46 DummyScaler(SDL_Surface* screen, int w, int h)
49 centerRectangle(m_area, GUI.Width, GUI.Height, w, h);
58 class Factory : public ScalerFactory
60 const char * getName() const
65 bool canEnable(int bpp, int w, int h) const
70 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
72 return new DummyScaler(screen, w, h);
76 static const Factory factory;
78 virtual const char * getName() const
83 virtual uint8* getDrawBuffer() const
85 const int Bpp = screen->format->BitsPerPixel / 8;
86 const int pitch = screen->pitch;
87 return ((uint8*) screen->pixels)
92 virtual unsigned int getDrawBufferPitch() const
97 virtual void getRenderedGUIArea(unsigned short & x, unsigned short & y,
98 unsigned short & w, unsigned short & h) const
100 x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h;
103 virtual void getRatio(float & x, float & y) const
108 virtual void prepare()
110 if (SDL_MUSTLOCK(m_screen)) SDL_LockSurface(m_screen);
113 virtual void finish()
115 if (SDL_MUSTLOCK(m_screen)) SDL_UnlockSurface(m_screen);
116 SDL_UpdateRects(m_screen, 1, &m_area);
119 virtual void pause() { };
120 virtual void resume() { };
122 virtual bool filter(const SDL_Event& event) { return false; };
124 const DummyScaler::Factory DummyScaler::factory;
126 /* Basic and slow software scaler */
128 class SWScaler : public Scaler
130 SDL_Surface * m_screen;
133 const int m_w, m_h, m_Bpp;
136 SWScaler(SDL_Surface* screen, int w, int h)
137 : m_screen(screen), m_w(w), m_h(h),
138 m_Bpp(m_screen->format->BitsPerPixel / 8)
140 centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2);
141 m_surface = reinterpret_cast<uint8*>(malloc(w * h * m_Bpp));
149 class Factory : public ScalerFactory
151 const char * getName() const
156 bool canEnable(int bpp, int w, int h) const
158 return w * 2 < GUI.Width && h * 2 < GUI.Height;
161 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
163 return new SWScaler(screen, w, h);
167 static const Factory factory;
169 virtual const char * getName() const
171 return "software 2x scaling";
174 uint8* getDrawBuffer() const
179 unsigned int getDrawBufferPitch() const
184 void getRenderedGUIArea(unsigned short & x, unsigned short & y,
185 unsigned short & w, unsigned short & h) const
187 x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h;
190 void getRatio(float & x, float & y) const
199 uint16 * src = reinterpret_cast<uint16*>(m_surface);
200 uint16 * dst = reinterpret_cast<uint16*>(
201 ((uint8*) m_screen->pixels)
203 + (m_area.y * m_screen->pitch));
204 const int src_pitch = m_w;
205 const int dst_pitch = m_screen->pitch / m_Bpp;
208 for (y = 0; y < m_h*2; y++) {
209 for (x = 0; x < m_w*2; x+=2) {
211 dst[x + 1] = src[x/2];
214 if (y&1) src += src_pitch;
217 SDL_UpdateRects(m_screen, 1, &m_area);
223 bool filter(const SDL_Event& event) { return false; };
225 const SWScaler::Factory SWScaler::factory;
227 /* Platform specific scalers */
230 class ARMScaler : public Scaler
232 SDL_Surface * m_screen;
235 const int m_w, m_h, m_Bpp;
238 ARMScaler(SDL_Surface* screen, int w, int h)
239 : m_screen(screen), m_w(w), m_h(h),
240 m_Bpp(m_screen->format->BitsPerPixel / 8)
242 centerRectangle(m_area, GUI.Width, GUI.Height, w * 2, h * 2);
243 m_surface = reinterpret_cast<uint8*>(malloc(w * h * m_Bpp));
251 class Factory : public ScalerFactory
253 const char * getName() const
258 bool canEnable(int bpp, int w, int h) const
260 return bpp == 16 && w * 2 < GUI.Width && h * 2 < GUI.Height &&
261 w % 16 == 0 /* asm assumes w div by 16 */;
264 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
266 return new ARMScaler(screen, w, h);
270 static const Factory factory;
272 virtual const char * getName() const
274 return "software ARM 2x scaling";
277 uint8* getDrawBuffer() const
282 unsigned int getDrawBufferPitch() const
287 void getRenderedGUIArea(unsigned short & x, unsigned short & y,
288 unsigned short & w, unsigned short & h) const
290 x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h;
293 void getRatio(float & x, float & y) const
299 SDL_FillRect(m_screen, NULL, 0);
304 if (SDL_MUSTLOCK(m_screen)) SDL_LockSurface(m_screen);
305 uint16 * src = reinterpret_cast<uint16*>(m_surface);
306 uint16 * dst = reinterpret_cast<uint16*>(
307 ((uint8*) m_screen->pixels)
309 + (m_area.y * m_screen->pitch));
310 const int src_pitch = m_w;
311 const int dst_pitch = m_screen->pitch / m_Bpp;
314 for (y = 0; y < m_h*2; y++) {
317 "mov r0, %0; mov r1, %1; mov r2, %2;"
318 "stmdb r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};"
319 "1: ldmia r1!,{r3,r4,r5,r6,r7,r8,r9,r10};"
320 "mov r14,r5,lsr #16;"
321 "mov r12,r5,lsl #16;"
322 "orr r14,r14,r14,lsl #16;"
323 "orr r12,r12,r12,lsr #16;"
324 "mov r11,r4,lsr #16;"
326 "orr r11,r11,r11,lsl #16;"
327 "orr r5,r5,r5,lsr #16;"
330 "orr r4,r4,r4,lsl #16;"
331 "orr r3,r3,r3,lsr #16;"
332 "stmia r0!,{r3,r4,r5,r11,r12,r14};"
335 "orr r3,r3,r3,lsr #16;"
336 "orr r4,r4,r4,lsl #16;"
339 "orr r5,r5,r5,lsr #16;"
340 "orr r6,r6,r6,lsl #16;"
343 "orr r7,r7,r7,lsr #16;"
344 "orr r8,r8,r8,lsl #16;"
345 "mov r12,r10,lsr #16;"
346 "mov r11,r10,lsl #16;"
347 "orr r12,r12,r12,lsl #16;"
348 "orr r11,r11,r11,lsr #16;"
349 "mov r10,r9,lsr #16;"
351 "orr r10,r10,r10,lsl #16;"
352 "orr r9,r9,r9,lsr #16;"
353 "stmia r0!,{r3,r4,r5,r6,r7,r8,r9,r10,r11,r12};"
356 "ldmia r13!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,r14};"
358 : "r" (dst), "r" (src), "r" (m_w)
359 : "r0", "r1", "r2", "r3"
362 if (y&1) src += src_pitch;
365 if (SDL_MUSTLOCK(m_screen)) SDL_UnlockSurface(m_screen);
367 if (m_screen->flags & SDL_DOUBLEBUF) {
370 SDL_UpdateRects(m_screen, 1, &m_area);
376 bool filter(const SDL_Event& event) { return false; };
378 const ARMScaler::Factory ARMScaler::factory;
382 class HAAScalerBase : public Scaler
384 SDL_Surface *m_screen;
387 const int m_w, m_h, m_Bpp;
388 const float ratio_x, ratio_y;
390 static bool initialized;
393 HAAScalerBase(SDL_Surface* screen, int w, int h, float r_x, float r_y)
394 : m_screen(screen), m_w(w), m_h(h),
395 m_Bpp(m_screen->format->BitsPerPixel / 8),
396 ratio_x(r_x), ratio_y(r_y)
398 const bool fullscreen = m_screen->flags & SDL_FULLSCREEN;
399 centerRectangle(m_area, GUI.Width, GUI.Height, w * r_x, h * r_y);
401 // Clear the SDL screen with black, just in case it gets drawn.
402 SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
408 HAA_SetVideoMode(); // Tell HAA we might have changed video mode
411 actor = HAA_CreateActor(0, m_w, m_h, m_screen->format->BitsPerPixel);
412 HAA_SetPosition(actor, m_area.x, m_area.y + (fullscreen ? 0 : 60));
413 // In windowed mode, take care of the title bar (xoffset = 60)
414 HAA_SetScale(actor, r_x, r_y);
419 virtual ~HAAScalerBase()
421 HAA_FreeActor(actor);
424 uint8* getDrawBuffer() const
426 return reinterpret_cast<uint8*>(actor->surface->pixels);
429 unsigned int getDrawBufferPitch() const
431 return actor->surface->pitch;
434 void getRenderedGUIArea(unsigned short & x, unsigned short & y,
435 unsigned short & w, unsigned short & h) const
437 x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h;
440 void getRatio(float & x, float & y) const
442 x = ratio_x; y = ratio_y;
458 bool filter(const SDL_Event& event)
460 return HAA_FilterEvent(&event) == 0;
463 bool HAAScalerBase::initialized = false;
465 class HAAFillScaler : public HAAScalerBase
467 HAAFillScaler(SDL_Surface* screen, int w, int h)
468 : HAAScalerBase(screen, w, h,
469 GUI.Width / (float)w, GUI.Height / (float)h)
474 class Factory : public ScalerFactory
476 const char * getName() const
481 bool canEnable(int bpp, int w, int h) const
486 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
488 return new HAAFillScaler(screen, w, h-20);
492 static const Factory factory;
494 const char * getName() const
496 return "HAA fill screen scaling";
499 const HAAFillScaler::Factory HAAFillScaler::factory;
501 class HAASquareScaler : public HAAScalerBase
503 HAASquareScaler(SDL_Surface* screen, int w, int h, float ratio)
504 : HAAScalerBase(screen, w, h, ratio, ratio)
509 class Factory : public ScalerFactory
511 const char * getName() const
516 bool canEnable(int bpp, int w, int h) const
521 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
523 return new HAASquareScaler(screen, w, h,
524 fminf(GUI.Width / (float)w, GUI.Height / (float)h));
528 static const Factory factory;
530 const char * getName() const
532 return "HAA square screen scaling";
535 const HAASquareScaler::Factory HAASquareScaler::factory;
540 class XSPScaler : public Scaler
542 SDL_Surface* m_screen;
544 SDL_Rect m_real_area;
545 bool m_should_enable, m_enabled; // Try to avoid flicker.
547 static void setDoubling(bool enable)
549 SDL_SysWMinfo wminfo;
550 SDL_VERSION(&wminfo.version);
551 if ( SDL_GetWMInfo(&wminfo) ) {
552 Display *dpy = wminfo.info.x11.display;
553 XSPSetPixelDoubling(dpy, 0, enable ? 1 : 0);
558 XSPScaler(SDL_Surface* screen, int w, int h)
559 : m_screen(screen), m_should_enable(true), m_enabled(false)
561 centerRectangle(m_area, GUI.Width, GUI.Height,
564 m_real_area.x = m_area.x;
565 m_real_area.y = m_area.y;
566 m_real_area.w = m_area.w / 2;
567 m_real_area.h = m_area.h / 2;
572 if (m_enabled) setDoubling(false);
575 class Factory : public ScalerFactory
577 const char * getName() const
582 bool canEnable(int bpp, int w, int h) const
584 return w * 2 < GUI.Width && h * 2 < GUI.Height;
587 Scaler* instantiate(SDL_Surface* screen, int w, int h) const
589 return new XSPScaler(screen, w, h);
593 static const Factory factory;
595 const char * getName() const
597 return "XSP pixel doubling";
600 uint8* getDrawBuffer() const
602 const int Bpp = screen->format->BitsPerPixel / 8;
603 const int pitch = screen->pitch;
604 return ((uint8*) screen->pixels)
606 + (m_area.y * pitch);
609 unsigned int getDrawBufferPitch() const
611 return screen->pitch;
614 void getRenderedGUIArea(unsigned short & x, unsigned short & y,
615 unsigned short & w, unsigned short & h) const
617 x = m_area.x; y = m_area.y; w = m_area.w; h = m_area.h;
620 void getRatio(float & x, float & y) const
627 if (m_should_enable && !m_enabled) {
635 SDL_UpdateRects(m_screen, 1, &m_real_area);
640 m_should_enable = false;
649 m_should_enable = true; // Will enable later
652 bool filter(const SDL_Event& event)
654 if (event.type == SDL_ACTIVEEVENT &&
655 (event.active.state & SDL_APPINPUTFOCUS)) {
656 if (event.active.gain) {
668 const XSPScaler::Factory XSPScaler::factory;
671 static const ScalerFactory* scalers[] = {
672 /* More useful scalers come first */
674 &XSPScaler::factory, /* n8x0 pixel doubling */
677 &ARMScaler::factory, /* arm 2x scaling */
680 &HAASquareScaler::factory, /* n900 animation actor scaling */
682 &SWScaler::factory, /* soft 2x scaling */
683 &DummyScaler::factory, /* failsafe */
684 /* The following scalers will not be automatically enabled, no matter what */
686 &HAAFillScaler::factory,
690 /* Entry point functions */
692 const ScalerFactory* searchForScaler(int bpp, int w, int h)
694 const int n = sizeof(scalers) / sizeof(ScalerFactory*);
697 if (Config.scaler && strcasecmp(Config.scaler, "help") == 0 ) {
699 printf("Scalers list:\n");
700 for (i = 0; i < n; i++) {
701 printf(" %s\n", scalers[i]->getName());
703 DIE("End of scalers list");
704 } else if (Config.scaler && strcasecmp(Config.scaler, "auto") != 0 ) {
705 // We prefer a specific scaler
706 for (i = 0; i < n; i++) {
707 if (strcasecmp(scalers[i]->getName(), Config.scaler) == 0) {
708 if (scalers[i]->canEnable(bpp, w, h)) {
709 // Found the scaler selected by the user, and we can use it.
713 "Selected scaler '%s' cannot be enabled in this mode\n",
715 break; // Fallback to another scaler.
720 fprintf(stderr, "Selected scaler '%s' does not exist\n",
725 // Just try them all now, in a buildtime set priority.
726 for (i = 0; i < n; i++) {
727 if (scalers[i]->canEnable(bpp, w, h)) {
732 DIE("Can't use any scaler; this shouldn't happen.");