static int numgroups=4; static int groupsizes[]={5,2,1,1}; #define init_grp 1 #define init_sub 'a' /* Also tests the following libretro env callbacks: */ //RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 //RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 //do not use the names as primary - they're an enum, the preprocessor can't read them #define PIXFMT 0//RETRO_PIXEL_FORMAT_0RGB1555 //#define PIXFMT 1//RETRO_PIXEL_FORMAT_XRGB8888 //#define PIXFMT 2//RETRO_PIXEL_FORMAT_RGB565 #if PIXFMT==0 #define pixel_t uint16_t #define p_red 0x7C00 #define p_grn 0x03E0 #define p_blu 0x001F #define p_x 0 #define p_dark 0x3DEF #endif #if PIXFMT==1 #define pixel_t uint32_t #define p_red 0xFF0000 #define p_grn 0x00FF00 #define p_blu 0x0000FF #define p_x 0xFF000000 #define p_dark 0x7F7F7F #endif #if PIXFMT==2 #define pixel_t uint16_t #define p_red 0xF800 #define p_grn 0x07E0 #define p_blu 0x001F #define p_x 0 #define p_dark 0x7BEF #endif #define p_blk 0 #define p_yel (p_red|p_grn) #define p_pur (p_red|p_blu) #define p_tel (p_grn|p_blu) #define p_wht (p_red|p_grn|p_blu) #include "libretro.h" #include #include #include #include #define PI 3.14159265358979323846 static retro_log_printf_t log_cb; static void log_null(enum retro_log_level level, const char *fmt, ...) {} retro_environment_t environ_cb = NULL; retro_video_refresh_t video_cb = NULL; retro_audio_sample_t audio_cb = NULL; retro_audio_sample_batch_t audio_batch_cb = NULL; retro_input_poll_t poller_cb = NULL; retro_input_state_t input_state_cb = NULL; static struct { int testgroup; int testsub; bool canchange; int frame; uint8_t test3a_activate; uint64_t test3a_last; uint16_t test4a[28*3]; } state; uint16_t inpstate[2]; bool sound_enable; pixel_t pixels[240*320]; void renderchr(pixel_t col, int chr, int x, int y); void renderstr(pixel_t col, const char * str, int x, int y); unsigned long crc32_calc(unsigned char *ptr, unsigned cnt, unsigned long crc); #if defined(__unix__) #include uint64_t cpu_features_get_time_usec() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec*1000000 + ts.tv_nsec/1000; } #elif defined(_WIN32) #include uint64_t cpu_features_get_time_usec() { static LARGE_INTEGER freq = {}; if (!freq.QuadPart) QueryPerformanceFrequency(&freq); LARGE_INTEGER count; QueryPerformanceCounter(&count); return count.QuadPart * 1000000 / freq.QuadPart; } #else uint64_t cpu_features_get_time_usec() { static uint64_t last = 0; last += 1000000; return last; } #endif static void test1a(void) { unsigned x, y; for (y=0;y<240;y++) for (x=0;x<320;x++) { pixels[y*320+x] = p_wht; } for (y=80;y<160;y++) for (x=0;x<80;x++) { pixels[y*320 + 40+x] = p_red; pixels[y*320 + 120+x] = p_grn; pixels[y*320 + 200+x] = p_blu; } } static void test1b(void) { unsigned x, y; for (x=0;x<320;x++) { if ((x+state.frame)%40 > 20) pixels[x] = p_blk; else pixels[x] = p_wht; } for (y=1;y<240;y++) memcpy(pixels+(320*y), pixels+0, sizeof(*pixels)*320); } static void test1c(void) { unsigned x,y; for (y=0;y<240;y++) { for (x=0;x<320;x++) { if (((240-y)+state.frame)%30 > 15) pixels[y*320+x]=p_blk|p_x; else pixels[y*320+x]=p_wht|p_x; } } } static void test1d(void) { int i; if (state.frame&1) { for (i=0;i<320*240;i++) pixels[i] = p_wht; } else { for (i=0;i<320*240;i++) pixels[i] = p_blk; } } static void test1e(void) { unsigned x, y; for (y=0;y<240;y++) { for (x=0;x<320;x++) { if ((y^x) & 1) pixels[y*320+x] = p_wht; else pixels[y*320+x] = p_blk; } } } static void test1f(void) { unsigned x, y; for (x=0;x<320*240;x++) { pixels[x] = p_wht; } for (x=0;x<320;x++) { pixels[ x] = ((x&1)?p_red:p_yel); pixels[239*320+x] = ((x&1)?p_yel:p_red); } for (y=0;y<240;y++) { pixels[y*320+ 0] = ((y&1)?p_red:p_yel); pixels[y*320+319] = ((y&1)?p_yel:p_red); } } static void test2a(void) { if (state.frame%240 >= 120) { memset(pixels, 0x00, sizeof(pixels)); memset(pixels+(320*(state.frame%120)*2), 0xFF, sizeof(*pixels)*2); sound_enable = true; } else { memset(pixels, 0xFF, sizeof(pixels)); memset(pixels+(320*(state.frame%120)*2), 0x00, sizeof(*pixels)*2); sound_enable = false; } } static void test2b(void) { if (inpstate[0]&0x0F0F) { memset(pixels, 0x00, sizeof(pixels)); sound_enable = true; } else { memset(pixels, 0xFF, sizeof(pixels)); sound_enable = false; } } static void formatnum(char* out, unsigned int in) { char tmp[16]; int pos=0; sprintf(tmp, "%.10u", in); while (tmp[pos] == '0') pos++; *out++ = tmp[pos++]; while (tmp[pos]) { if (pos%3 == 1) *out++ = ','; *out++ = tmp[pos++]; } *out='\0'; } static size_t test_inputspeed(void) { size_t calls = 0; uint64_t start = cpu_features_get_time_usec(); unsigned iterlen = 32; uint64_t now; double seconds; while (true) { unsigned i; now = cpu_features_get_time_usec(); if (now < start+10000 && iterlen<0x10000000) iterlen*=2; /* try to call the time function once per 10ms */ if (now > start+2000000) break; for (i=0;i>4)%2, RETRO_DEVICE_JOYPAD, 0, (now^i)%16); calls++; } } seconds = (double)(now-start) / 1000000.0; return calls/seconds; } static void test3a(void) { unsigned i; if (state.test3a_activate == 1) { state.test3a_last = test_inputspeed(); state.test3a_activate = 2; } if (state.test3a_activate == 0 && inpstate[0]&0xFF0F) state.test3a_activate = 1; if (state.test3a_activate == 2 && !inpstate[0]) state.test3a_activate = 0; for (i=0;i<320*240;i++) pixels[i] = p_wht; if (state.test3a_activate == 1) renderstr(p_blk, "Running...", 8, 16); else if (state.test3a_last == 0) renderstr(p_blk, "Ready", 8, 16); else { char line[128]; formatnum(line, state.test3a_last); strcat(line, " calls per second"); renderstr(p_blk, line, 8, 16); formatnum(line, state.test3a_last/60); strcat(line, " calls per frame"); renderstr(p_blk, line, 8, 24); } } static void test4a(void) { uint16_t color; unsigned i; if (inpstate[0] != state.test4a[27*3+1] || inpstate[1] != state.test4a[27*3+2]) { for (i=0;i<27*3;i++) state.test4a[0*3+i] = state.test4a[0*3+i+3]; state.test4a[27*3+0] = state.frame+1; state.test4a[27*3+1] = inpstate[0]; state.test4a[27*3+2] = inpstate[1]; } color = (~crc32_calc((unsigned char*)state.test4a, 6*28, ~0U))&p_dark; for (i=0;i<320*240;i++) pixels[i] = color; for (i=0;i<28;i++) { if (state.test4a[i*3+0]) { char line[17]; sprintf(line, "%i: %.4X %.4X", state.test4a[i*3+0], state.test4a[i*3+1], state.test4a[i*3+2]); renderstr(p_wht, line, 8, 8+i*8); } } } void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; } void retro_set_audio_sample(retro_audio_sample_t cb) { audio_cb = cb; } void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; } void retro_set_input_poll(retro_input_poll_t cb) { poller_cb = cb; } void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } void retro_set_environment(retro_environment_t cb) { environ_cb = cb; bool True = true; environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &True); #if 0 environ_cb(RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, &frametime_g); environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf); #endif } void retro_init(void) { struct retro_log_callback log; if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) log_cb = log.log; else log_cb = log_null; log_cb(RETRO_LOG_DEBUG, "0123 test"); log_cb(RETRO_LOG_DEBUG, "%.3i%c t%st", 12, '3', "es"); } void retro_deinit(void) {} unsigned retro_api_version(void) { return RETRO_API_VERSION; } void retro_get_system_info(struct retro_system_info *info) { const struct retro_system_info myinfo = { "minir test core", "v1.00", "c|h", false, false }; memcpy(info, &myinfo, sizeof(myinfo)); } void retro_get_system_av_info(struct retro_system_av_info* info) { static const struct retro_system_av_info myinfo = { { 320, 240, 320, 240, 0.0 }, { 60.0, 30720.0 } }; memcpy(info, &myinfo, sizeof(myinfo)); } void retro_set_controller_port_device(unsigned port, unsigned device) {} void retro_reset(void) { memset(&state, 0, sizeof(state)); state.testgroup = init_grp; state.testsub = init_sub; } void retro_run(void) { unsigned i; char testid[3]; poller_cb(); inpstate[0] = 0x0000; inpstate[1] = 0x0000; for (i=0;i<16;i++) { inpstate[0] |= (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i))<>ix)&1) pixels[(y+iy)*320 + x+(ix^7)]=col; } } } void renderstr(pixel_t col, const char * str, int x, int y) { int i; for (i=0;str[i];i++) renderchr(col, str[i], x+i*8, y); } /* Karl Malbrain's compact CRC-32. * See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": * http://www.geocities.ws/malbrain/ */ unsigned long Crc32[] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; unsigned long crc32_calc (unsigned char *ptr, unsigned cnt, unsigned long crc) { while( cnt-- ) { crc = ( crc >> 4 ) ^ Crc32[(crc & 0xf) ^ (*ptr & 0xf)]; crc = ( crc >> 4 ) ^ Crc32[(crc & 0xf) ^ (*ptr++ >> 4)]; } return crc; }