示例#1
0
文件: video.c 项目: fhgwright/fs-uae
void fs_emu_video_after_update() {
    fs_emu_video_buffer_unlock();
    int64_t t = fs_emu_monotonic_time();

    if (fs_emu_cursor_is_visible_to() > 0) {
        if (fs_emu_cursor_is_visible_to() < fs_emu_monotonic_time()) {
            //fs_log("%lld\n", fs_emu_monotonic_time());
            fs_emu_show_cursor(0);
        }
    }

    update_leds(t);

    update_video_stats_system_video();

    if (g_fs_emu_benchmark_start_time) {
        static int64_t last_report = 0;
        if (t - last_report > 5000000) {
            double ttime = ((t - g_fs_emu_benchmark_start_time) / 1000000.0);
            double sys_fps = g_fs_emu_total_sys_frames / ttime;
            double emu_fps = g_fs_emu_total_emu_frames / ttime;
            //fs_log("average fps sys: %0.1f emu: %0.1f\n", sys_fps, emu_fps);
            printf("average fps sys: %0.1f emu: %0.1f\n", sys_fps, emu_fps);
            last_report = t;
        }
    }
}
示例#2
0
文件: video.c 项目: fhgwright/fs-uae
static void update_video_stats_system_video()
{
    if (g_fs_emu_benchmark_start_time > 0) {
        g_fs_emu_total_sys_frames++;
    }

    static int64_t frame_time_first = 0;
    static int64_t frame_time_last = 0;
    int t = fs_emu_monotonic_time();
    if (frame_time_first == 0) {
        frame_time_first = t;
    }
    int time_ms = (t - frame_time_first) / 1000;
    int dt = (int) (time_ms - frame_time_last);
    // more than 5 seconds => do not record entry (abnormality)
    fs_emu_stat_queue_add_entry(&g_fs_emu_sys_frame_times, dt, 5 * 1000);
    frame_time_last = time_ms;
    double refresh_rate = fs_ml_get_refresh_rate();
    // check if we have missed a vblank internal, but only after 2 seconds
    // after first render
    if (time_ms > 2000 && refresh_rate > 0) {
        if (dt > 1.5 * 1000.0 / refresh_rate) {
            g_fs_emu_lost_vblanks++;
        }
    }
}
示例#3
0
文件: emu.c 项目: eehrich/fs-uae
static void on_quit() {
    fs_log("libfsemu:on_quit\n");
    g_fs_emu_quit_time = fs_emu_monotonic_time();
    if (g_quit_function) {
        g_quit_function();
    }
    // FIXME: detached?
    fs_thread_create("force-quit", force_quit_thread, NULL);
}
示例#4
0
文件: video.c 项目: fhgwright/fs-uae
void fs_emu_update_video_stats_1() {
    int t = fs_emu_monotonic_time();
    if (g_frame_time_first == 0) {
        return;
    }
    int time_ms = (t - g_frame_time_first) / 1000;

    int dt = (int) (time_ms - g_frame_time_last);
    // more than 5 seconds => do not record entry (abnormality)
    fs_emu_stat_queue_add_entry(&g_fs_emu_emu2_frame_times, dt, 5 * 1000);
}
示例#5
0
文件: emu.c 项目: eehrich/fs-uae
int fs_emu_run(fs_emu_main_function function) {
    fs_emu_log("fs_emu_run, main_function at %p\n", function);

    // FIXME: should wait until we are certain that the video thread is
    // running (i.e. wait for a status / flag)

#ifdef WITH_NETPLAY
    // FIXME: MOVE
    if (fs_emu_netplay_enabled()) {
        fs_log("netplay is enabled\n");
        fs_emu_netplay_start();
    }
#endif

    g_emulation_thread = fs_thread_create(
                             "emulation", emulation_thread_entry, function);
    if (g_emulation_thread == NULL) {
        fs_emu_log("error starting video thread\n");
        // FIXME: ERROR MESSAGE HERE
        // FIXME: FATAL
    }

#ifdef FS_EMU_DRIVERS
    int result = fs_emu_main_loop();
#else
    int result = fs_ml_main_loop();
#endif
    fs_emu_log("fs_emu_run: main loop is done\n");

    if (g_fs_emu_benchmark_start_time) {
        int64_t t2 = fs_emu_monotonic_time();
        double ttime = ((t2 - g_fs_emu_benchmark_start_time) / 1000000.0);
        double sys_fps = g_fs_emu_total_sys_frames / ttime;
        double emu_fps = g_fs_emu_total_emu_frames / ttime;
        fs_log("average fps sys: %0.1f emu: %0.1f\n", sys_fps, emu_fps);
    }

    fs_emu_log("fs_emu_run: waiting for emulation thread to stop\n");
    while (g_fs_emu_emulation_thread_running) {
        fs_emu_msleep(1);
    }
    fs_emu_log("fs_emu_run: emulation thread stopped\n");

#ifdef USE_SDL_AUDIO
    fs_emu_log("fs_emu_run: calling SDL_CloseAudio\n");
    SDL_CloseAudio();
#endif

    fs_emu_audio_shutdown();
    fs_emu_log("fs_emu_run: returning\n");
    return result;
}
示例#6
0
文件: emu.c 项目: FrodeSolheim/fs-uae
static void on_quit()
{
    g_fs_emu_quit_time = fs_emu_monotonic_time();
    /*
    if (g_post_quit_function) {
        fs_log("libfsemu on_quit: executing quit function\n");
        g_post_quit_function();
    } else {
        fs_log("libfsemu on_quit: no quit function\n");
    }
    */
    // FIXME: detached?
    fs_thread_create("force-quit", force_quit_thread, NULL);
}
示例#7
0
文件: emu.c 项目: alpine9000/fs-uae
static int wait_for_frame_no_netplay(void)
{
#if 0
    while (1) {
        fs_ml_usleep(100 * 1000);
    }
#endif

    if (g_fs_emu_benchmarking) {
        return 1;
    }
#ifdef FSE_DRIVERS
    if (g_fs_emu_benchmark_mode) {
        return 1;
    }
#endif
    if (!g_fs_emu_throttling) {
        return 1;
    }
    //fs_log("wait_for_frame_no_netplay\n");
    static int64_t last_time = 0;
    static int64_t frame_time = 0;
    if (last_time == 0) {
        last_time = fs_emu_monotonic_time();
    }

    static double last_frame_rate = 0.0;
    double frame_rate = fs_emu_get_video_frame_rate();
    if (frame_rate != last_frame_rate) {
        frame_time = ((int64_t) 1000000) / frame_rate;
        fs_log("wait_for_frame_no_netplay: new frame rate %0.2f (time: %d)\n",
               frame_rate, (int) frame_time);
        last_frame_rate = frame_rate;
    }

    int64_t wait_until = last_time + frame_time;
    //int64_t sleep_until = wait_until;
    int64_t sleep_until = wait_until - 100;
    int64_t t = fs_emu_monotonic_time();
    //fs_log("%lld %lld\n", sleep_until, t);
    while (t < sleep_until) {
        int64_t sleep_time = sleep_until - t;
        //fs_log("%lld %lld %lld\n", sleep_until, t, sleep_time);
        fs_ml_usleep(sleep_time);
        t = fs_emu_monotonic_time();
    }
    while (t < wait_until) {
        t = fs_emu_monotonic_time();
    }
    last_time = last_time + frame_time;
    if (fs_emu_monotonic_time() > last_time + frame_time) {
        // time has elapsed too far, probably due to pause function having
        // been used
        last_time = fs_emu_monotonic_time();
    }
    return 1;
}
示例#8
0
文件: render.c 项目: nekoniaow/fs-uae
static void full_sleep_until_vsync() {
    // FIXME: use this instead of sleep_until_vsync
    int sleep_time = 0;
    int time_left = 3000;
    int64_t t = fs_emu_monotonic_time();
    if (g_fs_ml_target_frame_time > 0) {
        sleep_time = g_sleep_until_vsync_last_time +
                g_fs_ml_target_frame_time - t - time_left;
    }
    if (sleep_time > g_fs_ml_target_frame_time - time_left) {
        sleep_time = 0;
    }
    if (sleep_time > 0) {
        fs_ml_usleep(sleep_time);
    }
}
示例#9
0
文件: render.c 项目: nekoniaow/fs-uae
static void sleep_until_vsync() {
    int sleep_time = 5000;
    int64_t t = fs_emu_monotonic_time();
    //int64_t sleep_until = 0;
    if (g_fs_ml_target_frame_time > 0) {
        // calculate sleep time based on frame rate
        // (allowing 4 ms busy-waiting by OpenGL driver, if necessary)
        //sleep_time = g_fs_ml_target_frame_time - 4000;
        sleep_time = g_sleep_until_vsync_last_time +
                g_fs_ml_target_frame_time - t - 5000;
    }
    if (sleep_time > g_fs_ml_target_frame_time - 4000) {
        sleep_time = 0;
    }
    if (sleep_time > 0) {
        //printf("sleep %d\n", sleep_time);
        fs_ml_usleep(sleep_time);
    }
}
示例#10
0
/**
 * This function is called at the end of the frame rendering function
 */
static void handle_quit_sequence() {
    int fade_time = 750 * 1000;

    int64_t dt = fs_emu_monotonic_time() - g_fs_emu_quit_time;
    if (dt > fade_time && g_fs_emu_emulation_thread_stopped) {
        fs_emu_log("calling fs_ml_stop because emu thread is done\n");
        fs_ml_stop();

    }
    else if (dt > 5 * 1000 * 1000) {
        // 5 seconds has passed after shutdown was requested
        fs_emu_log("calling fs_ml_stop because emu does not stop\n");
        // FIXME: FORCE STOP
        fs_ml_stop();
        fs_emu_log("force-closing the emulator\n");
        exit(1);
    }

    // fade out over 750ms
    float fade = (1.0 * dt) / fade_time;
    if (fade > 1.0) {
        fade = 1.0;
    }

    // draw fading effect
    fs_gl_viewport(0, 0, fs_ml_video_width(), fs_ml_video_height());
    fs_gl_ortho_hd();
    fs_gl_blending(1);
    fs_gl_texturing(0);
    fs_gl_color4f(0.0, 0.0, 0.0, fade);
    GLfloat vert[] = {
        0, 0,
        1920, 0,
        1920, 1080,
        0, 1080
    };
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, vert);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    glDisableClientState(GL_VERTEX_ARRAY);
    CHECK_GL_ERROR();
}
示例#11
0
文件: render.c 项目: nekoniaow/fs-uae
static void render_iteration_vsync() {
    if (g_fs_ml_video_sync_low_latency) {
        int current_frame_at_start = g_available_frame;

        //int64_t t1 = fs_ml_monotonic_time();

        int sleep_time = 0;
        int time_left = g_estimated_upload_render_duration;
        int64_t t = fs_emu_monotonic_time();
        if (g_fs_ml_target_frame_time > 0) {
            sleep_time = g_estimated_next_vblank_time - t - time_left;
        }
        if (sleep_time > g_fs_ml_target_frame_time - time_left) {
            sleep_time = 0;
        }
        if (sleep_time > 0) {
            fs_ml_usleep(sleep_time);
        }

        if (g_available_frame > current_frame_at_start) {
            //printf("low latency %d\n", g_available_frame);
        }
        else {
            //printf("...\n");
        }
    }

    update_frame();
    CHECK_GL_ERROR_MSG("update_frame");
    render_frame();
    CHECK_GL_ERROR_MSG("render_frame");

    //opengl_fence(FENCE_SET);
    //glFlush();
    //opengl_fence(FENCE_WAIT);
    //int64_t upload_render_time = fs_ml_monotonic_time() - t1;
    //printf("urt %lld\n", upload_render_time);

    opengl_swap_synchronous();

    g_measured_vblank_time = fs_ml_monotonic_time();
    g_vblank_count++;
    fs_mutex_lock(g_vblank_mutex);
    g_measured_vblank_times[g_vblank_index] = g_measured_vblank_time;
    g_vblank_index = (g_vblank_index + 1) % VBLANK_COUNT;
    fs_mutex_unlock(g_vblank_mutex);

    // FIXME: adjust g_measured_vblank_time based on historical data (smooth out
    // irregularities) and save the result in g_adjusted_vblank_time
    g_adjusted_vblank_time = g_measured_vblank_time;

    g_sleep_until_vsync_last_time = g_adjusted_vblank_time;
    g_estimated_next_vblank_time = g_adjusted_vblank_time + \
            g_fs_ml_target_frame_time;

    // g_start_new_frame_cond is used to signal that a new frame can be
    // generated when the emulation is running in sync - this is not used
    // when only display flipping is synced to vblank

    fs_mutex_lock(g_start_new_frame_mutex);
    g_start_new_frame = 1;
    fs_condition_signal(g_start_new_frame_cond);
    fs_mutex_unlock(g_start_new_frame_mutex);
}
示例#12
0
文件: sdl.c 项目: alpine9000/fs-uae
int fs_ml_video_create_window(const char *title)
{
    fs_log("fs_ml_video_create_window\n");
    g_window_title = g_strdup(title);

    g_fs_ml_keyboard_input_grab = fs_config_get_boolean(
            "keyboard_input_grab");
    if (g_fs_ml_automatic_input_grab == FS_CONFIG_NONE) {
        g_fs_ml_keyboard_input_grab = 1;
    }
    fs_log("keyboard input grab: %d\n", g_fs_ml_keyboard_input_grab);

    static int initialized = 0;

    SDL_SetHint(SDL_HINT_GRAB_KEYBOARD,
                g_fs_ml_keyboard_input_grab ? "1" : "0");
    SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
#ifdef WINDOWS
    SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1");
#endif

    SDL_Init(SDL_INIT_VIDEO);

    SDL_version cversion, lversion;
    SDL_VERSION(&cversion);
    SDL_GetVersion(&lversion);
    fs_log("[SDL] Version %d.%d.%d (Compiled against %d.%d.%d)\n",
           lversion.major, lversion.minor, lversion.patch,
           cversion.major, cversion.minor, cversion.patch);

    if (!initialized) {
        int display_index = 0;
        SDL_DisplayMode mode;
        int error = SDL_GetCurrentDisplayMode(display_index, &mode);
        if (error) {
            fs_log("SDL_GetCurrentDisplayMode failed\n");
            SDL_ShowSimpleMessageBox(
                SDL_MESSAGEBOX_ERROR, "Display Error",
                "SDL_GetCurrentDisplayMode failed.", NULL);
            exit(1);
        }

        fs_emu_monitor_init();

        const char *mon = fs_config_get_const_string("monitor");
        int mon_flag = -1;
        if (mon == NULL) {
            mon = "middle-left";
        }
        if (strcmp(mon, "left") == 0) {
            mon_flag = FS_EMU_MONITOR_FLAG_LEFT;
        } else if (strcmp(mon, "middle-left") == 0) {
            mon_flag = FS_EMU_MONITOR_FLAG_MIDDLE_LEFT;
        } else if (strcmp(mon, "middle-right") == 0) {
            mon_flag = FS_EMU_MONITOR_FLAG_MIDDLE_RIGHT;
        } else if (strcmp(mon, "right") == 0) {
            mon_flag = FS_EMU_MONITOR_FLAG_RIGHT;
        }
        else {
            mon_flag = FS_EMU_MONITOR_FLAG_MIDDLE_LEFT;
        }
        FSEmuMonitor monitor;
        fs_emu_monitor_get_by_flag(mon_flag, &monitor);
        fs_log("Monitor \"%s\" (flag %d) => index %d\n",
               mon, mon_flag, monitor.index);
        g_display = monitor.index;

        g_fullscreen_width = fs_config_get_int("fullscreen_width");
        if (g_fullscreen_width == FS_CONFIG_NONE) {
            g_fullscreen_width = mode.w;
        }
        g_fullscreen_height = fs_config_get_int("fullscreen_height");
        if (g_fullscreen_height == FS_CONFIG_NONE) {
            g_fullscreen_height = mode.h;
        }

        if (g_fs_emu_video_fullscreen_mode_string == NULL) {
            g_fs_emu_video_fullscreen_mode = -1;
        }
        else if (g_ascii_strcasecmp(g_fs_emu_video_fullscreen_mode_string,
                "window") == 0) {
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_WINDOW;
        }
        else if (g_ascii_strcasecmp(g_fs_emu_video_fullscreen_mode_string,
                "fullscreen") == 0) {
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_FULLSCREEN;
        }
        else if (g_ascii_strcasecmp(g_fs_emu_video_fullscreen_mode_string,
                "desktop") == 0) {
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_DESKTOP;
        }
        if (g_fs_emu_video_fullscreen_mode == -1) {
#ifdef MACOSX
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_FULLSCREEN;
#else
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_FULLSCREEN;
#endif
            fs_log("[SDL] Defaulting to fullscreen_mode = desktop for SDL 2\n");
            g_fs_emu_video_fullscreen_mode = FULLSCREEN_DESKTOP;
        }

        initialized = 1;
    }

    if (g_fs_ml_video_sync) {
        g_fs_ml_vblank_sync = 1;
    }

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    if (g_fsaa) {
        fs_log("setting FSAA samples to %d\n", g_fsaa);
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, g_fsaa);
    }

    g_window_width = fs_config_get_int("window_width");
    if (g_window_width == FS_CONFIG_NONE) {
        g_window_width = 1920 / 2;
    }
    g_window_height = fs_config_get_int("window_height");
    if (g_window_height == FS_CONFIG_NONE) {
        g_window_height = 1080/ 2;
    }
    g_window_x = fs_config_get_int("window_x");
    if (g_window_x == FS_CONFIG_NONE) {
        g_window_x = SDL_WINDOWPOS_CENTERED;
    }
    g_window_y = fs_config_get_int("window_y");
    if (g_window_y == FS_CONFIG_NONE) {
        g_window_y = SDL_WINDOWPOS_CENTERED;
    }
    g_window_resizable = fs_config_get_boolean("window_resizable");
    if (g_window_resizable == FS_CONFIG_NONE) {
        g_window_resizable = 1;
    }

    g_fs_ml_automatic_input_grab = fs_config_get_boolean(
            "automatic_input_grab");
    if (g_fs_ml_automatic_input_grab == FS_CONFIG_NONE) {
        if (fs_ml_mouse_integration()) {
            g_fs_ml_automatic_input_grab = 0;
        } else {
            g_fs_ml_automatic_input_grab = 1;
        }
    }
    fs_log("automatic input grab: %d\n", g_fs_ml_automatic_input_grab);

    g_initial_input_grab = g_fs_ml_automatic_input_grab;
    if (fs_config_get_boolean("initial_input_grab") == 1) {
        g_initial_input_grab = 1;
    }
    else if (fs_config_get_boolean("initial_input_grab") == 0 ||
            // deprecated names:
            fs_config_get_boolean("input_grab") == 0 ||
            fs_config_get_boolean("grab_input") == 0) {
        g_initial_input_grab = 0;
    }

    set_video_mode();

    if (g_fs_ml_vblank_sync) {
        fs_emu_log("*** Setting swap interval to 1 ***\n");
        if (SDL_GL_SetSwapInterval(1) != 0) {
            fs_emu_warning("SDL_GL_SetSwapInterval(1) failed");
        }
    }
    else {
        fs_emu_log("*** Setting swap interval to 0 ***\n");
        SDL_GL_SetSwapInterval(0);
    }

    fs_log("initial input grab: %d\n", g_initial_input_grab);
    if (g_initial_input_grab && !g_has_input_grab) {
        fs_ml_set_input_grab(true);
    }
    fs_ml_show_cursor(0, 1);

    /* This looks a bit peculiar, but it helps to show the window in
     * fullscreen mode as soon as possible to reduce flickering,
       at least under GNOME 3. */
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    SDL_GL_SwapWindow(g_fs_ml_window);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    SDL_GL_SwapWindow(g_fs_ml_window);
    int64_t start_time = fs_emu_monotonic_time();
    SDL_Event event;
    while (fs_emu_monotonic_time() - start_time < 100 * 1000) {
        SDL_WaitEventTimeout(&event, 10);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        SDL_GL_SwapWindow(g_fs_ml_window);
    }

    // this function must be called from the video thread
    fs_log("init_opengl\n");
    fse_init_video_opengl();

    SDL_StartTextInput();

#ifdef WINDOWS
    if (!fs_config_false(OPTION_RAW_INPUT)) {
        fs_ml_init_raw_input();
    }
#endif

    fs_log("create windows is done\n");
    return 1;
}