5d05b9d3e9
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
235 lines
7.3 KiB
C
235 lines
7.3 KiB
C
#include "plugin.h"
|
|
|
|
#include "fixedpoint.h"
|
|
#include "lib/helper.h"
|
|
#include "lib/pluginlib_exit.h"
|
|
|
|
|
|
#include "SDL.h"
|
|
#include "SDL_video.h"
|
|
|
|
#ifdef COMBINED_SDL
|
|
#error deprecated
|
|
#endif
|
|
|
|
/* SDL program */
|
|
extern int my_main(int argc, char *argv[]);
|
|
|
|
void *audiobuf = NULL;
|
|
|
|
unsigned int sdl_thread_id, main_thread_id;
|
|
|
|
bool printf_enabled = true;
|
|
|
|
static void (*exit_cb)(void) = NULL;
|
|
|
|
/* sets the exit handler presented to the program */
|
|
void rbsdl_atexit(void (*cb)(void))
|
|
{
|
|
if(exit_cb)
|
|
{
|
|
rb->splash(HZ, "WARNING: multiple exit handlers!");
|
|
}
|
|
exit_cb = cb;
|
|
}
|
|
|
|
/* called by program */
|
|
void rb_exit(int rc)
|
|
{
|
|
if(rb->thread_self() == main_thread_id) /* rockbox main thread */
|
|
exit(rc);
|
|
else
|
|
rb->thread_exit();
|
|
}
|
|
|
|
/* exit handler, called by rockbox */
|
|
void cleanup(void)
|
|
{
|
|
if(exit_cb)
|
|
exit_cb();
|
|
|
|
if(exit_cb != SDL_Quit)
|
|
SDL_Quit();
|
|
|
|
#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) && !defined(RB_PROFILE)
|
|
#define USE_TIMER
|
|
#endif
|
|
|
|
#ifdef USE_TIMER
|
|
/* stop timer callback if there is one, since the memory it
|
|
* resides in could be overwritten */
|
|
rb->timer_unregister();
|
|
#endif
|
|
|
|
if(audiobuf)
|
|
memset(audiobuf, 0, 4); /* clear */
|
|
|
|
backlight_use_settings();
|
|
|
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
|
rb->cpu_boost(false);
|
|
#endif
|
|
}
|
|
|
|
/* 256KB */
|
|
static long main_stack[1024 * 1024 / 2];
|
|
int (*main_fn)(int argc, char *argv[]);
|
|
int prog_idx;
|
|
static void main_thread(void)
|
|
{
|
|
char *fallback[] = { "/blah", NULL };
|
|
|
|
#ifdef COMBINED_SDL
|
|
char **argv = programs[prog_idx].argv ? programs[prog_idx].argv : fallback;
|
|
int argc = programs[prog_idx].argv ? programs[prog_idx].argc : 1;
|
|
#else
|
|
char **argv = fallback;
|
|
int argc = 1;
|
|
#endif
|
|
|
|
int rc = main_fn(argc, argv);
|
|
if(rc != 0)
|
|
rb->splash(HZ * 2, SDL_GetError());
|
|
|
|
rb->thread_exit();
|
|
}
|
|
|
|
#if defined(CPU_ARM) && !defined(SIMULATOR)
|
|
#define CR_M (1 << 0) /* MMU enable */
|
|
#define CR_A (1 << 1) /* Alignment abort enable */
|
|
#define CR_C (1 << 2) /* Dcache enable */
|
|
#define CR_W (1 << 3) /* Write buffer enable */
|
|
#define CR_P (1 << 4) /* 32-bit exception handler */
|
|
#define CR_D (1 << 5) /* 32-bit data address range */
|
|
#define CR_L (1 << 6) /* Implementation defined */
|
|
#define CR_B (1 << 7) /* Big endian */
|
|
#define CR_S (1 << 8) /* System MMU protection */
|
|
#define CR_R (1 << 9) /* ROM MMU protection */
|
|
#define CR_F (1 << 10) /* Implementation defined */
|
|
#define CR_Z (1 << 11) /* Implementation defined */
|
|
#define CR_I (1 << 12) /* Icache enable */
|
|
#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
|
|
#define CR_RR (1 << 14) /* Round Robin cache replacement */
|
|
#define CR_L4 (1 << 15) /* LDR pc can set T bit */
|
|
#define CR_DT (1 << 16)
|
|
#ifdef CONFIG_MMU
|
|
#define CR_HA (1 << 17) /* Hardware management of Access Flag */
|
|
#else
|
|
#define CR_BR (1 << 17) /* MPU Background region enable (PMSA) */
|
|
#endif
|
|
#define CR_IT (1 << 18)
|
|
#define CR_ST (1 << 19)
|
|
#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */
|
|
#define CR_U (1 << 22) /* Unaligned access operation */
|
|
#define CR_XP (1 << 23) /* Extended page tables */
|
|
#define CR_VE (1 << 24) /* Vectored interrupts */
|
|
#define CR_EE (1 << 25) /* Exception (Big) Endian */
|
|
#define CR_TRE (1 << 28) /* TEX remap enable */
|
|
#define CR_AFE (1 << 29) /* Access flag enable */
|
|
#define CR_TE (1 << 30) /* Thumb exception enable */
|
|
|
|
#define __LINUX_ARM_ARCH__ ARM_ARCH
|
|
|
|
#if __LINUX_ARM_ARCH__ >= 7
|
|
#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
|
|
#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
|
|
#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")
|
|
#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
|
|
#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
|
: : "r" (0) : "memory")
|
|
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
|
: : "r" (0) : "memory")
|
|
#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
|
|
: : "r" (0) : "memory")
|
|
#elif defined(CONFIG_CPU_FA526)
|
|
#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
|
|
: : "r" (0) : "memory")
|
|
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
|
: : "r" (0) : "memory")
|
|
#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
|
|
#else
|
|
#define isb(x) __asm__ __volatile__ ("" : : : "memory")
|
|
#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
|
|
: : "r" (0) : "memory")
|
|
#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
|
|
#endif
|
|
|
|
static inline unsigned long get_cr(void)
|
|
{
|
|
unsigned long val;
|
|
asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc");
|
|
return val;
|
|
}
|
|
|
|
static inline void set_cr(unsigned long val)
|
|
{
|
|
asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
|
|
: : "r" (val) : "cc");
|
|
isb();
|
|
}
|
|
#endif
|
|
|
|
enum plugin_status plugin_start(const void *param)
|
|
{
|
|
(void) param;
|
|
|
|
#if defined(CPU_ARM) && !defined(SIMULATOR)
|
|
/* (don't) set alignment trap. Will generate a data abort
|
|
* exception on ARM. */
|
|
set_cr(get_cr() | CR_A);
|
|
#endif
|
|
|
|
#if 0
|
|
char c = *((char*)NULL);
|
|
|
|
/* test alignment trap */
|
|
unsigned int x = 0x12345678;
|
|
char *p = ((char*)&x) + 1;
|
|
unsigned short *p2 = (unsigned short*)p;
|
|
rb->splashf(HZ, "%04x, %02x%02x", *p2, *(p+1), *p);
|
|
#endif
|
|
|
|
/* don't confuse this with the main SDL thread! */
|
|
main_thread_id = rb->thread_self();
|
|
|
|
/* we always use the audio buffer */
|
|
size_t sz;
|
|
audiobuf = rb->plugin_get_audio_buffer(&sz);
|
|
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
|
|
if ((uintptr_t)audiobuf < (uintptr_t)plugin_start_addr)
|
|
{
|
|
uint32_t tmp_size = (uintptr_t)plugin_start_addr - (uintptr_t)audiobuf;
|
|
sz = MIN(sz, tmp_size);
|
|
}
|
|
#endif
|
|
|
|
/* wipe sig */
|
|
rb->memset(audiobuf, 0, sz);
|
|
if(init_memory_pool(sz, audiobuf) == (size_t) -1)
|
|
{
|
|
rb->splashf(HZ*2, "TLSF init failed!");
|
|
return PLUGIN_ERROR;
|
|
}
|
|
|
|
main_fn = my_main;
|
|
|
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
|
rb->cpu_boost(true);
|
|
#endif
|
|
|
|
backlight_ignore_timeout();
|
|
/* set the real exit handler */
|
|
#undef rb_atexit
|
|
rb_atexit(cleanup);
|
|
|
|
/* make a new thread to use a bigger stack and higher priority than otherwise accessible */
|
|
sdl_thread_id = rb->create_thread(main_thread, main_stack,
|
|
sizeof(main_stack), 0, "sdl_main"
|
|
IF_PRIO(, PRIORITY_USER_INTERFACE) // we need other threads still
|
|
IF_COP(, CPU));
|
|
rb->thread_wait(sdl_thread_id);
|
|
|
|
rb->sleep(HZ); /* wait a second in case there's an error message on screen */
|
|
|
|
return PLUGIN_OK;
|
|
}
|