/* Check time elapsed after one frame, hold up * the program if not enough tim has elapsed */ void adjust_to_framerate() { // EMSCRIPTEN had its own ways to run frames at certain FPS #ifndef EMSCRIPTEN char title_buf[100]; current_ticks = get_timestamp_micro(); uint64_t ticks_elapsed = current_ticks - last_ticks; uint64_t estimated_ticks = last_ticks + (uint64_t)(1000 * (1000/framerate)); uint64_t framerate_ticks = ticks_elapsed * framerate; // If too fast we sleep for a certain amount of time // sleep might go over the time we want to wait // so attempt to come out of sleep early and use // cpu cycles to wait for the rest of the time if (limiter && framerate_ticks < 1000000) { uint64_t delay_time = 1000000/framerate - ticks_elapsed; if (delay_time >= 5000) { //casting uint64_t into uint32_t, not really safe // but we will never be delaying for more than 1000ms which is well in range SDL_Delay( (uint32_t) ((delay_time - 200)/1000)); } while(get_timestamp_micro() < estimated_ticks) ;; } current_ticks = get_timestamp_micro(); count = (count + 1) % 60; if (count == 0) { //printf("speed %u\n", current_ticks - last_ticks); float fps = 1000000.0 / (current_ticks - last_ticks); //printf("Gameboy fps:%.2f\n",fps); SDL_WM_SetCaption(title_buf,""); #ifdef THREE_DS int fps_i = (int)fps; if (fps_i > 35) { show_fps(fps); forgiveness_frame = 1; } else if (forgiveness_frame) { // Benefit of the doubt forgiveness_frame = 0; } else { // Beyond the forgiveness threshold, framerate is low show_fps(fps); } show_battery(); show_fps_limiter(); #endif } last_ticks = current_ticks; #endif }
int run_emu(const char *path) { SceCtrlData pad; unsigned int joypad1, joypad2; setup_audio(); emu->set_sample_rate(44100); emu->set_equalizer(Nes_Emu::nes_eq); emu->set_palette_range(0); vita2d_texture *tex = vita2d_create_empty_texture(Nes_Emu::image_width, Nes_Emu::image_height); void *tex_data = vita2d_texture_get_datap(tex); static uint32_t video_buffer[Nes_Emu::image_width * Nes_Emu::image_height]; emu->set_pixels(video_buffer, Nes_Emu::image_width); Auto_File_Reader freader(path); emu->load_ines(freader); int scale = 2; int pos_x = SCREEN_W/2 - (Nes_Emu::image_width/2)*scale; int pos_y = SCREEN_H/2 - (Nes_Emu::image_height/2)*scale; while (1) { sceCtrlPeekBufferPositive(0, &pad, 1); if ((pad.buttons & CHANGE_GAME_MASK) == CHANGE_GAME_MASK) break; joypad1 = joypad2 = update_input(&pad); emu->emulate_frame(joypad1, joypad2); const Nes_Emu::frame_t &frame = emu->frame(); const uint8_t *in_pixels = frame.pixels; uint32_t *out_pixels = (uint32_t *)tex_data; for (unsigned h = 0; h < Nes_Emu::image_height; h++, in_pixels += frame.pitch, out_pixels += Nes_Emu::image_width) { for (unsigned w = 0; w < Nes_Emu::image_width; w++) { unsigned col = frame.palette[in_pixels[w]]; const Nes_Emu::rgb_t& rgb = emu->nes_colors[col]; unsigned r = rgb.red; unsigned g = rgb.green; unsigned b = rgb.blue; out_pixels[w] = 0xFF000000 | (r << 0) | (g << 8) | (b << 16); } } vita2d_start_drawing(); vita2d_clear_screen(); vita2d_draw_texture_scale(tex, pos_x, pos_y, scale, scale); show_fps(); vita2d_end_drawing(); vita2d_swap_buffers(); } return 0; }
void do_idle(void) { int i; struct timeval now; if (refresh_screen) { draw_screen(); refresh_screen = 0; gettimeofday(&last_busy, 0); } switch (state) { case AttractLoop: if (over_fps(2)) return; grab_video_in(); write_video_frame_zoom(video_r.min, video_in, VIDEO_ZOOM); break; case Live: if (over_fps(30)) return; grab_video_in(); memcpy(frames[0], video_in, sizeof(frames[0])); /* FALLTHROUGH */ case Frozen: for (i=0; i<nhist; i++) transform(history[i], frames[i], frames[i+1]); write_video_frame_zoom(video_r.min, &frames[nhist], VIDEO_ZOOM); gettimeofday(&now, 0); if (idletime > 0 && elapsed_time(last_busy, now) > idletime) { nhist = 0; unfreeze(); draw_screen(); state = AttractLoop; } if (fps_flag) show_fps(); break; } }
/*** * Callback for when a new frame is generated that we need to render. */ bool retro_video_refresh_callback(const void *data, unsigned width, unsigned height, size_t pitch) { curr_frame++; // initialize our main render texture once we get the dimensions for the first time if (!tex) { tex = vita2d_create_empty_texture_format(width, height, SCE_GXM_TEXTURE_FORMAT_R5G6B5); tex_data = vita2d_texture_get_datap(tex); // initialize PSPImage if (Screen) free(Screen); int size = width * height * 2; Screen = (PspImage*)malloc(sizeof(PspImage)); Screen->TextureFormat = SCE_GXM_TEXTURE_FORMAT_R5G6B5; Screen->PalSize = (unsigned short)0; memset(tex_data, 0, size); Screen->Width = width; Screen->Height = height; Screen->Pixels = tex_data; Screen->Texture = tex; Screen->Viewport.X = 0; Screen->Viewport.Y = 0; Screen->Viewport.Width = width; Screen->Viewport.Height = height; int i; for (i = 1; i < width; i *= 2); Screen->PowerOfTwo = (i == width); Screen->BytesPerPixel = 2; Screen->FreeBuffer = 0; Screen->Depth = 16; } // initialize our render variables if they're uninitalized, or // if they've changed due to user action if(OptionsChanged) { OptionsChanged = false; // handle changes to scale from the options switch (Options.DisplayMode) { case DISPLAY_MODE_UNSCALED: scale_x = 1.0f; scale_y = 1.0f; break; case DISPLAY_MODE_2X: scale_x = 2.0f; scale_y = 2.0f; break; case DISPLAY_MODE_FIT_HEIGHT: scale_y = (float)SCREEN_H / (float)height; scale_x = scale_y; break; case DISPLAY_MODE_FILL_SCREEN: scale_x = (float)SCREEN_W / (float)width; scale_y = (float)SCREEN_H / (float)height; break; } curr_frame = 0; curr_fps = 0.0f; pos_x = (SCREEN_W / 2) - (width / 2) * scale_x; pos_y = (SCREEN_H / 2) - (height / 2) * scale_y; // handle texture filtering options tex_filter = Options.TextureFilter ? SCE_GXM_TEXTURE_FILTER_LINEAR : SCE_GXM_TEXTURE_FILTER_POINT; sceGxmTextureSetMinFilter(&(tex->gxm_tex), tex_filter); sceGxmTextureSetMagFilter(&(tex->gxm_tex), tex_filter); } // copy the input pixels into the output buffer const uint16_t* in_pixels = (const uint16_t*)data; uint16_t *out_pixels = (uint16_t *)tex_data; for (h = 0; h < height; h++, in_pixels += pitch / 2, out_pixels += width) { memcpy(out_pixels, in_pixels, width * sizeof(uint16_t)); } // draw the screen vita2d_start_drawing(); vita2d_draw_texture_scale(tex, pos_x, pos_y, scale_x, scale_y); if(Options.ShowFps) show_fps(); vita2d_end_drawing(); vita2d_swap_buffers(); return true; }
void update_screen(void) { UINT8 skipped_it = skiptable[frameskip][frameskip_counter]; if (!skipped_it) { if (option_showfps) show_fps(); draw_volume_status(1); show_battery_warning(); ui_show_popup(1); } else { draw_volume_status(0); ui_show_popup(0); } if (warming_up) { sceDisplayWaitVblankStart(); last_skipcount0_time = ticker() - (int)((float)FRAMESKIP_LEVELS * PSP_TICKS_PER_FRAME); warming_up = 0; } if (frameskip_counter == 0) this_frame_base = last_skipcount0_time + (int)((float)FRAMESKIP_LEVELS * PSP_TICKS_PER_FRAME); frames_displayed++; frames_since_last_fps++; if (!skipped_it) { TICKER curr = ticker(); int flip = 0; if (option_speedlimit) { TICKER target = this_frame_base + (int)((float)frameskip_counter * PSP_TICKS_PER_FRAME); if (option_vsync) { if (curr < target - 100) { video_flip_screen(1); flip = 1; } } while (curr < target) curr = ticker(); } if (!flip) video_flip_screen(0); rendered_frames_since_last_fps++; if (frameskip_counter == 0) { float seconds_elapsed = (float)(curr - last_skipcount0_time) * (1.0 / 1000000.0); float frames_per_sec = (float)frames_since_last_fps / seconds_elapsed; game_speed_percent = (int)(100.0 * frames_per_sec / PSP_REFRESH_RATE + 0.5); frames_per_second = (int)((float)rendered_frames_since_last_fps / seconds_elapsed + 0.5); last_skipcount0_time = curr; frames_since_last_fps = 0; rendered_frames_since_last_fps = 0; if (option_autoframeskip) { if (option_speedlimit && frames_displayed > 2 * FRAMESKIP_LEVELS) { if (game_speed_percent >= 99) { frameskipadjust++; if (frameskipadjust >= 3) { frameskipadjust = 0; if (frameskip > 0) frameskip--; } } else { if (game_speed_percent < 80) { frameskipadjust -= (90 - game_speed_percent) / 5; } else if (frameskip < 8) { frameskipadjust--; } while (frameskipadjust <= -2) { frameskipadjust += 2; if (frameskip < FRAMESKIP_LEVELS - 1) frameskip++; } } } } } } frameskip_counter = (frameskip_counter + 1) % FRAMESKIP_LEVELS; }