예제 #1
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;
}
예제 #2
0
파일: render.c 프로젝트: nekoniaow/fs-uae
static void opengl_fence(int command) {
#ifdef USE_GLES

#else
    if (command == FENCE_SET) {
        if (g_has_nv_fence) {
            //printf("...\n");
            glSetFenceNV(g_fence, GL_ALL_COMPLETED_NV);
            CHECK_GL_ERROR_MSG("glSetFenceNV(g_fence, GL_ALL_COMPLETED_NV)");
        }
        else if (g_has_apple_fence) {
            glSetFenceAPPLE(g_fence);
            CHECK_GL_ERROR_MSG("glSetFenceAPPLE(g_fence)");
        }
        else if (g_has_arb_sync) {
            g_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
            CHECK_GL_ERROR_MSG("glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)");
        }
    }
    else if (command == FENCE_WAIT) {
        if (g_has_nv_fence) {
            //printf("-- f --\n");
            //glFinishFenceNV(g_fence);
            //int64_t t1 = fs_get_monotonic_time();
            //fs_ml_usleep(10000);
            while (!glTestFenceNV(g_fence)) {
                CHECK_GL_ERROR_MSG("glTestFenceNV(g_fence)");
                //printf("-> %lld\n", fs_get_monotonic_time() - t1);
                //printf("%d\n", glGetError());
                fs_ml_usleep(1000);
                //printf("-> %lld\n", fs_get_monotonic_time() - t1);
            }
            CHECK_GL_ERROR_MSG("glTestFenceNV(g_fence)");
        }
        else if (g_has_apple_fence) {
            while (!glTestFenceAPPLE(g_fence)) {
                CHECK_GL_ERROR_MSG("glTestFenceAPPLE(g_fence)");
                fs_ml_usleep(1000);
            }
            CHECK_GL_ERROR_MSG("glTestFenceAPPLE(g_fence)");
        }
        else if (g_has_arb_sync) {
            int flags = GL_SYNC_FLUSH_COMMANDS_BIT;
            while (glClientWaitSync(g_sync, flags, 0)
                    == GL_TIMEOUT_EXPIRED) {
                CHECK_GL_ERROR_MSG("glClientWaitSync(g_sync, flags, 0)");
                flags = 0;
                fs_ml_usleep(1000);
            }
            CHECK_GL_ERROR_MSG("glClientWaitSync(g_sync, flags, 0)");
        }
    }
#endif
}
예제 #3
0
파일: emu.c 프로젝트: alpine9000/fs-uae
static void *force_quit_thread(void *data)
{
    for (int i = 0; i < 10; i++) {
        fs_ml_usleep(1000 * 1000);
        fs_log("force_quit_thread: %d seconds passed\n", i + 1);
    }
    fs_log("force_quit_thread: should force quit (FIXME: not implemented)\n");
    printf("force_quit_thread: should force quit (FIXME: not implemented)\n");
    return NULL;
}
예제 #4
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);
    }
}
예제 #5
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);
    }
}
예제 #6
0
파일: mouse.c 프로젝트: alpine9000/fs-uae
static void init_manymouse(void)
{
    /* On OS X with HIDManager driver at least, the mice must be polled from
     * the same thread as the one which called ManyMouse_Init, so we do
     * everything (also enumeration in a worker thread) and wait for
     * enumeration to complete.*/

    fs_log("[MANYMOUSE] Copyright (c) 2005-2012 Ryan C. Gordon\n");
    g_manymouse_thread = fs_thread_create("manymouse", manymouse_thread, NULL);
    if (g_manymouse_thread == NULL) {
        fs_log("[MANYMOUSE] Error - could not create ManyMouse thread\n");
        // ManyMouse_Quit();
    } else {
        while (g_manymouse_last_index < 0) {
            fs_ml_usleep(1000);
        }
        g_fs_ml_input_device_count = g_manymouse_last_index;
    }
}
예제 #7
0
파일: render.c 프로젝트: nekoniaow/fs-uae
void fs_ml_render_iteration() {
    static int first = 1;
    if (first) {
        first = 0;
        initialize_opengl_sync();
    }

    if (g_fs_ml_vblank_sync) {
        render_iteration_vsync();
    }
    else if (g_fs_ml_benchmarking) {
        update_frame();
        render_frame();
        swap_opengl_buffers();
    }
    else {
        // when vsync is off, we wait until a new frame is ready and
        // then we display it immediately

        if (fs_ml_is_quitting()) {
            // but when the emulation is quitting, we can't expect any new
            // frames so there's no point waiting for them. Instead, we just
            // sleep a bit to throttle the frame rate for the quit animation
            fs_ml_usleep(10000);
        } else {
            // wait max 33 ms to allow the user interface to work even if
            // the emu hangs
            // int64_t dest_time = fs_get_real_time() + 33 * 1000;
            int64_t end_time = fs_condition_get_wait_end_time(33 * 1000);
            int64_t check_time = 0;

            fs_mutex_lock(g_frame_available_mutex);
            // fs_log("cond wait until %lld\n", end_time);
            while (g_rendered_frame == g_available_frame) {
                fs_condition_wait_until(
                    g_frame_available_cond, g_frame_available_mutex, end_time);
                check_time = fs_condition_get_wait_end_time(0);
                if (check_time >= end_time) {
                    // fs_log("timed out at %lld\n", check_time);
                    break;
                } else {
                    // fs_log("wake-up at %lld (end_time = %lld)\n", check_time, end_time);
                }
            }
            fs_mutex_unlock(g_frame_available_mutex);
        }

        update_frame();
        render_frame();
        swap_opengl_buffers();
        //gl_finish();
    }

    if (g_fs_ml_video_screenshot_path) {
        fs_mutex_lock(g_fs_ml_video_screenshot_mutex);
        if (g_fs_ml_video_screenshot_path) {
            save_screenshot_of_opengl_framebuffer(
                    g_fs_ml_video_screenshot_path);
            g_free(g_fs_ml_video_screenshot_path);
            g_fs_ml_video_screenshot_path = NULL;
        }
        fs_mutex_unlock(g_fs_ml_video_screenshot_mutex);
    }

    if (g_fs_ml_video_post_render_function) {
        g_fs_ml_video_post_render_function();
    }
}
예제 #8
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);
}
예제 #9
0
파일: emu.c 프로젝트: alpine9000/fs-uae
void fs_emu_msleep(int msec)
{
    fs_ml_usleep(msec * 1000);
}
예제 #10
0
파일: mouse.c 프로젝트: alpine9000/fs-uae
static void *manymouse_thread(void* data)
{
    fs_log("[MANYMOUSE] Thread running\n");

    int k = g_fs_ml_input_device_count;
    g_first_manymouse_index = k;
    int mouse_count = ManyMouse_Init();
    if (mouse_count < 0) {
        fs_log("[MANYMOUSE] Initialization failed (%d)\n", mouse_count);
    }
    else if (mouse_count == 0) {
        fs_log("MANYMOUSE: no mice found\n");
        // no mice found, so we just quit using the library
    }

    for (int i = 0; i < mouse_count; i++) {
        const char *device = ManyMouse_DeviceName(i);
        const char *driver = ManyMouse_DriverName();

        char *name;
        if (device[0] == 0 || g_ascii_strcasecmp(device, "mouse") == 0) {
            name = g_strdup("Mouse: Unnamed Mouse");
        } else {
            name = g_strdup_printf("Mouse: %s", device);
        }
        // fs_ml_input_unique_device_name either returns name, or frees it
        // and return another name, so name must be malloced and owned by
        // caller
        name = fs_ml_input_unique_device_name(name);
        fs_log("MANYMOUSE: Adding %s (%s)\n", name, driver);

        g_fs_ml_input_devices[k].type = FS_ML_MOUSE;
        g_fs_ml_input_devices[k].index = k;
        g_fs_ml_input_devices[k].name = name;
        g_fs_ml_input_devices[k].alias = g_strdup_printf("MOUSE #%d", i + 2);
        k += 1;
    }

    // when done like this, I believe no memory barrier is needed when the
    // other thread polls g_manymouse_last_index
    g_manymouse_last_index = k;

    if (mouse_count < 0) {
        // ManyMouse library was not initialized
        return NULL;
    }

    ManyMouseEvent event;
    fs_ml_event *new_event;
    while (!fs_ml_is_quitting()) {
        // printf("..\n");
        while (ManyMouse_PollEvent(&event)) {
            // printf(" -- event type %d -- \n", event.type);
            if (event.type == MANYMOUSE_EVENT_RELMOTION) {
                // printf("MANYMOUSE_EVENT_RELMOTION\n");
                new_event = fs_ml_alloc_event();
                new_event->type = FS_ML_MOUSEMOTION;
                new_event->motion.device = g_first_manymouse_index + \
                        event.device;
                if (event.item == 0) {
                    new_event->motion.xrel = event.value;
                    new_event->motion.yrel = 0;
                }
                else if (event.item == 1) {
                    new_event->motion.xrel = 0;
                    new_event->motion.yrel = event.value;
                }
                new_event->motion.x = FS_ML_NO_ABSOLUTE_MOUSE_POS;
                new_event->motion.y = FS_ML_NO_ABSOLUTE_MOUSE_POS;

                fs_ml_post_event(new_event);
                // ManyMouseEventType type;
                // unsigned int device;
                // unsigned int item;
                // int value;
                // int minval;
                // int maxval;
            }
            else if (event.type == MANYMOUSE_EVENT_BUTTON) {
                db_log(input, "MANYMOUSE: EVENT_BUTTON "
                       "device %d item %d value %d\n",
                       event.device, event.item, event.value);
                new_event = fs_ml_alloc_event();
                new_event->type = event.value ? FS_ML_MOUSEBUTTONDOWN :
                        FS_ML_MOUSEBUTTONUP;
                new_event->button.state = event.value != 0;
                new_event->button.device = g_first_manymouse_index + \
                        event.device;
                if (event.item == 0) {
                    new_event->button.button = FS_ML_BUTTON_LEFT;
                }
                else if (event.item == 1) {
                    new_event->button.button = FS_ML_BUTTON_RIGHT;
                }
                else if (event.item == 2) {
                    new_event->button.button = FS_ML_BUTTON_MIDDLE;
                }
                else {
                    new_event->button.button = 0;
                }
                fs_ml_post_event(new_event);
            }
            else if (event.type == MANYMOUSE_EVENT_ABSMOTION) {
                // printf("MANYMOUSE_EVENT_ABSMOTION\n");
            }
            else if (event.type == MANYMOUSE_EVENT_SCROLL) {
                db_log(input, "MANYMOUSE: EVENT_SCROLL "
                       "device %d item %d value %d\n",
                       event.device, event.item, event.value);
                new_event = fs_ml_alloc_event();
                new_event->type = FS_ML_MOUSEBUTTONDOWN;
                new_event->button.state = 1;
                new_event->button.device = g_first_manymouse_index + \
                        event.device;
                new_event->button.button = 0;
                if (event.item == 0) {
                    if (event.value == 1) {
                        new_event->button.button = FS_ML_BUTTON_WHEELUP;
                    }
                    else {
                        new_event->button.button = FS_ML_BUTTON_WHEELDOWN;
                    }
                }
                fs_ml_post_event(new_event);
            }
        }
        fs_ml_usleep(1000);
    }

    ManyMouse_Quit();
    return NULL;
}
예제 #11
0
파일: emu.c 프로젝트: eehrich/fs-uae
static void *force_quit_thread(void *data) {
    for (int i = 0; i < 5; i++) {
        fs_ml_usleep(1000 * 1000);
    }
    return NULL;
}