Exemple #1
0
void vsyncarch_verticalblank(video_canvas_t *c, float rate, int frames)
{
    unsigned long nowi, lastx, max, frm, vbl;

    if (c->refreshrate <= 0.0f)
        return;

    nowi = vsyncarch_frequency();

    /* calculate counter cycles per frame */
    frm = (unsigned long)((float)(nowi * frames) / rate);

    nowi = vsyncarch_gettime();

    lastx = last - (frm * nosynccount);
    max = (frm * 7) >> 3;
    vbl = 0;
    while (max >= (nowi - lastx)) {
        IDirectDraw2_WaitForVerticalBlank(c->dd_object2, DDWAITVB_BLOCKBEGIN,
                                          0);
        nowi = vsyncarch_gettime();
        vbl = 1;
    }
    if ((!vbl) && (nosynccount < 16)) {
        nosynccount ++;
    } else {
        last = nowi;
        nosynccount = 0;
    }
}
Exemple #2
0
static void network_hook_connected_send(void)
{
    BYTE *local_event_buf = NULL;
    unsigned int send_len;
    BYTE send_len4[4];

    /* create and send current event buffer */
    network_event_record(EVENT_LIST_END, NULL, 0);
    send_len = network_create_event_buffer(&local_event_buf, &(frame_event_list[current_frame]));

#ifdef NETWORK_DEBUG
    t1 = vsyncarch_gettime();
#endif

    util_int_to_le_buf4(send_len4, (int)send_len);
    if (network_send_buffer(network_socket, send_len4, 4) < 0
        || network_send_buffer(network_socket, local_event_buf, send_len) < 0) {
        ui_display_statustext(translate_text(IDGS_REMOTE_HOST_DISCONNECTED), 1);
        network_disconnect();
    }
#ifdef NETWORK_DEBUG
    t2 = vsyncarch_gettime();
#endif

    lib_free(local_event_buf);
}
void vsyncarch_verticalblank(video_canvas_t *c, float rate, int frames)
{
    unsigned long nowi, lastx, max, frm, vbl;

    if (c->refreshrate <= 0.0f) {
        return;
    }

    nowi = vsyncarch_frequency();

    /* calculate counter cycles per frame */
    frm = (unsigned long)((float)(nowi * frames) / rate);

    nowi = vsyncarch_gettime();

    lastx = last - (frm * nosynccount);
    max = (frm * 7) >> 3;
    vbl = 0;
    while (max >= (nowi - lastx)) {
        vsyncarch_sync_with_raster(c);
        nowi = vsyncarch_gettime();
        vbl = 1;
    }
    if ((!vbl) && (nosynccount < 16)) {
        nosynccount++;
    } else {
        last = nowi;
        nosynccount = 0;
    }
}
Exemple #4
0
static void network_test_delay(void)
{
    int i, j;
    BYTE new_frame_delta;
    BYTE buf[0x60];
    long packet_delay[NUM_OF_TESTPACKETS];
    char st[256];

    vsyncarch_init();

    ui_display_statustext(translate_text(IDGS_TESTING_BEST_FRAME_DELAY), 0);

    if (network_mode == NETWORK_SERVER_CONNECTED) {
        for (i = 0; i < NUM_OF_TESTPACKETS; i++) {
            *((unsigned long*)buf) = vsyncarch_gettime();
            if (network_send_buffer(network_socket, buf, sizeof(buf)) < 0
                || network_recv_buffer(network_socket, buf, sizeof(buf)) < 0)
                return;
            packet_delay[i] = vsyncarch_gettime() - *((unsigned long*)buf);
        }
        /* Sort the packets delays*/
        for (i = 0; i < NUM_OF_TESTPACKETS - 1; i++) {
            for (j = i + 1; j < NUM_OF_TESTPACKETS; j++) {
                if (packet_delay[i] < packet_delay[j]) {
                    long d = packet_delay[i];
                    packet_delay[i] = packet_delay[j];
                    packet_delay[j] = d;
                }
            }
#ifdef NETWORK_DEBUG
            log_debug("packet_delay[%d]=%ld",i,packet_delay[i]);
#endif
        }
#ifdef NETWORK_DEBUG
        log_debug("vsyncarch_frequency = %ld", vsyncarch_frequency());
#endif
        /* calculate delay with 90% of packets beeing fast enough */
        /* FIXME: This needs some further investigation */
        new_frame_delta = 5 + (BYTE)(vsync_get_refresh_frequency()
                            * packet_delay[(int)(0.1 * NUM_OF_TESTPACKETS)]
                            / (float)vsyncarch_frequency());
        network_send_buffer(network_socket, &new_frame_delta,
                            sizeof(new_frame_delta));
    } else {
        /* network_mode == NETWORK_CLIENT */
        for (i = 0; i < NUM_OF_TESTPACKETS; i++) {
            if (network_recv_buffer(network_socket, buf, sizeof(buf)) <  0
                || network_send_buffer(network_socket, buf, sizeof(buf)) < 0)
                return;
        }
        network_recv_buffer(network_socket, &new_frame_delta,
                            sizeof(new_frame_delta));
    }
    network_free_frame_event_list();
    frame_delta = new_frame_delta;
    network_init_frame_event_list();
    sprintf(st, translate_text(IDGS_USING_D_FRAMES_DELAY), frame_delta);
    log_debug("netplay connected with %d frames delta.", frame_delta);
    ui_display_statustext(st, 1);
}
Exemple #5
0
void vsyncarch_sleep(signed long delay)
{
    unsigned long start, now;

    if (delay <= vsyncarch_frequency() / 1000)
        return;

    start = vsyncarch_gettime();
    do {
        Sleep(1);
        now = vsyncarch_gettime();
    } while (((signed long)(now - start)) < delay);
}
Exemple #6
0
static void archdep_create_mutex_sem(HMTX *hmtx, const char *pszName, int fState)
{
    APIRET rc;

    char *sem = lib_malloc(13+strlen(pszName) + 5 + 1);

    sprintf(sem, "\\SEM32\\VICE2\\%s_%04x", pszName, vsyncarch_gettime()&0xffff);

    rc = DosCreateMutexSem(sem, hmtx, 0, fState);
}
Exemple #7
0
/* ------------------------------------------------------------------------ */
void archdep_create_mutex_sem(HMTX *hmtx, const char *pszName, int fState)
{
    APIRET rc;

    char *sem = lib_malloc(13+strlen(pszName) + 5 + 1);

    sprintf(sem, "\\SEM32\\VICE2\\%s_%04x", pszName, vsyncarch_gettime()&0xffff);

    if (rc = DosCreateMutexSem(sem, hmtx, 0, fState)) {
        log_error(archlog, "DosCreateMutexSem '%s' (rc=%i)", pszName, rc);
    }
}
Exemple #8
0
void vsyncarch_prepare_vbl(void)
{
    /* keep vertical blank data prepared */
    last = vsyncarch_gettime();
    nosynccount = 0;
}
/* This is called at the end of each screen frame. It flushes the
   audio buffer and keeps control of the emulation speed. */
int vsync_do_vsync(struct video_canvas_s *c, int been_skipped)
{
    static unsigned long next_frame_start = 0;
    unsigned long network_hook_time = 0;

    /*
     * these are the counters to show how many frames are skipped
     * since the last vsync_display_speed
     */
    static int frame_counter = 0;
    static int skipped_frames = 0;

    /*
     * This are the frames which are skipped in a row
     */
    static int skipped_redraw = 0;

    /* Adjustment of frame output frequency. */
    static unsigned long adjust_start;
    static int frames_adjust;
    static signed long avg_sdelay, prev_sdelay;

    double sound_delay;
    int skip_next_frame;

    signed long delay;
    long frame_ticks_remainder, frame_ticks_integer, compval;

#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    float refresh_cmp;
    int refresh_div;
#endif

#ifdef HAVE_NETWORK
    /* check if someone wants to connect remotely to the monitor */
    monitor_check_remote();
#endif

    vsync_frame_counter++;

    /*
     * process everything wich should be done before the synchronisation
     * e.g. OS/2: exit the programm if trigger_shutdown set
     */
    vsyncarch_presync();

    /* Run vsync jobs. */
    if (network_connected()) {
        network_hook_time = vsyncarch_gettime();
    }

    vsync_hook();

    if (network_connected()) {
        network_hook_time = vsyncarch_gettime() - network_hook_time;

        if (network_hook_time > (unsigned long)frame_ticks) {
            next_frame_start += network_hook_time;
            now += network_hook_time;
        }
    }

#ifdef DEBUG
    /* switch between recording and playback in history debug mode */
    debug_check_autoplay_mode();
#endif

    /*
     * Update display every two second (pc system time)
     * This has some reasons:
     *  - we have a better statistic in case of a fastly running emulator
     *  - we don't slow down fast emulations by updating this value
     *    too often (eg more then 10 times a second)
     *  - I don't want to have a value jumping around for example
     *    between 99% and 101% if the user chooses 100% (s.above)
     *  - We need some statistict to get an avarage number for the
     *    frame-rate without staticstics it would also jump around
     */
    frame_counter++;

    if (!speed_eval_suspended &&
            (signed long)(now - display_start) >= 2 * vsyncarch_freq) {
        display_speed(frame_counter - skipped_frames);
        display_start = now;
        frame_counter = 0;
        skipped_frames = 0;
    }

    if (been_skipped) {
        skipped_frames++;
    }

    /* Flush sound buffer, get delay in seconds. */
    sound_delay = sound_flush();

    /* Get current time, directly after getting the sound delay. */
    now = vsyncarch_gettime();

    /* Start afresh after pause in frame output. */
    if (speed_eval_suspended) {
        speed_eval_suspended = 0;

        speed_eval_prev_clk = maincpu_clk;

        display_start = now;
        frame_counter = 0;
        skipped_frames = 0;

        next_frame_start = now;
        skipped_redraw = 0;
    }

    /* Start afresh after "out of sync" cases. */
    if (sync_reset) {
        sync_reset = 0;

        adjust_start = now;
        frames_adjust = 0;
        avg_sdelay = 0;
        prev_sdelay = 0;

        frame_ticks = (frame_ticks_orig + frame_ticks) / 2;
    }


    /* This is the time between the start of the next frame and now. */
    delay = (signed long)(now - next_frame_start);
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    refresh_cmp = (float)(c->refreshrate / refresh_frequency);
    refresh_div = (int)(refresh_cmp + 0.5f);
    refresh_cmp /= (float)refresh_div;

    if ((timer_speed == 100) && (!warp_mode_enabled) &&
            vsyncarch_vbl_sync_enabled() &&
            (refresh_cmp <= 1.02f) && (refresh_cmp > 0.98f) &&
            (refresh_div == 1)) {
        vsyncarch_verticalblank(c, c->refreshrate, refresh_div);
        skip_next_frame = 0;
        skipped_redraw = 0;
    } else {
#endif
        /*
         * We sleep until the start of the next frame, if:
         *  - warp_mode is disabled
         *  - a limiting speed is given
         *  - we have not reached next_frame_start yet
         *
         * We could optimize by sleeping only if a frame is to be output.
         */
        /*log_debug("vsync_do_vsync: sound_delay=%f  frame_ticks=%d  delay=%d", sound_delay, frame_ticks, delay);*/
        if (!warp_mode_enabled && timer_speed && delay < 0) {
            vsyncarch_sleep(-delay);
        }
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
        vsyncarch_prepare_vbl();
#endif
        /*
         * Check whether we should skip the next frame or not.
         * Allow delay of up to one frame before skipping frames.
         * Frames are skipped:
         *  - only if maximum skipped frames are not reached
         *  - if warp_mode enabled
         *  - if speed is not limited or we are too slow and
         *    refresh rate is automatic or fixed and needs correction
         *
         * Remark: The time_deviation should be the equivalent of two
         *         frames and must be scaled to make sure, that we
         *         don't start skipping frames before the CPU reaches 100%.
         *         If we are becoming faster a small deviation because of
         *         threading results in a frame rate correction suddenly.
         */
        frame_ticks_remainder = frame_ticks % 100;
        frame_ticks_integer = frame_ticks / 100;
        compval = frame_ticks_integer * 3 * timer_speed
                  + frame_ticks_remainder * 3 * timer_speed / 100;
        if (skipped_redraw < MAX_SKIPPED_FRAMES
                && (warp_mode_enabled
                    || (skipped_redraw < refresh_rate - 1)
                    || ((!timer_speed || delay > compval)
                        && !refresh_rate
                       )
                   )
           ) {
            skip_next_frame = 1;
            skipped_redraw++;
        } else {
            skip_next_frame = 0;
            skipped_redraw = 0;
        }
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    }
#endif

    /*
     * Check whether the hardware can keep up.
     * Allow up to 0,25 second error before forcing a correction.
     */
    if ((signed long)(now - next_frame_start) >= vsyncarch_freq / 8) {
#if !defined(__OS2__) && !defined(DEBUG)
        if (!warp_mode_enabled && relative_speed) {
            log_warning(LOG_DEFAULT, "Your machine is too slow for current settings!");
        }
#endif
        vsync_sync_reset();
        next_frame_start = now;
    }

    /* Adjust frame output frequency to match sound speed.
       This only kicks in for cycle based sound and SOUND_ADJUST_EXACT. */
    if (frames_adjust < INT_MAX) {
        frames_adjust++;
    }

    /* Adjust audio-video sync */
    if (!network_connected()
            && (signed long)(now - adjust_start) >= vsyncarch_freq / 5) {
        signed long adjust;
        avg_sdelay /= frames_adjust;
        /* Account for both relative and absolute delay. */
        adjust = (avg_sdelay - prev_sdelay + avg_sdelay / 8) / frames_adjust;
        /* Maximum adjustment step 1%. */
        if (labs(adjust) > frame_ticks / 100) {
            adjust = adjust / labs(adjust) * frame_ticks / 100;
        }
        frame_ticks -= adjust;

        frames_adjust = 0;
        prev_sdelay = avg_sdelay;
        avg_sdelay = 0;

        adjust_start = now;
    } else {
        /* Actual sound delay is sound delay minus vsync delay. */
        signed long sdelay = (signed long)(sound_delay * vsyncarch_freq);
        avg_sdelay += sdelay;
    }

    next_frame_start += frame_ticks;

    vsyncarch_postsync();
#if 0
    FILE *fd = fopen("latencylog.txt", "a");
    fprintf(fd, "%d %ld %ld %lf\n",
            vsync_frame_counter, frame_ticks, delay, sound_delay * 1000000);
    fclose(fd);
#endif
    return skip_next_frame;
}
Exemple #10
0
void mouse_move(int x, int y)
{
    mouse_x += x * mouse_accelx;
    mouse_y -= y * mouse_accely;
    mouse_timestamp = vsyncarch_gettime();
}
Exemple #11
0
void mouse_button(HWND hwnd, ULONG msg, MPARAM mp1)
{
    if (!_mouse_enabled) {
        return;
    }

    switch (msg) {
        case WM_MOUSEMOVE:
            _mouse_x = SHORT1FROMMP(mp1);
            _mouse_y = SHORT2FROMMP(mp1);
            mouse_timestamp = vsyncarch_gettime();
            {
                SWP swp;

                WinQueryWindowPos(hwnd, &swp);
                //
                // check whether the pointer is outside or inside the window
                //

                if (FullscreenIsNow()) {
                    visible = TRUE;
                }

                if (_mouse_x >= 0 && _mouse_x < swp.cx && _mouse_y >= 0 && _mouse_y < swp.cy) {
                    //
                    // FIXME: Don't capture the mouse pointer if it is in front
                    // of a client dialog!
                    //
                    if (WinQueryCapture(HWND_DESKTOP)!= hwnd && hide_mouseptr && !FullscreenIsNow()) {
                        WinSetCapture(HWND_DESKTOP, hwnd);
                    }

                    if (visible && hide_mouseptr && !FullscreenIsNow()) {
                        WinShowPointer(HWND_DESKTOP, FALSE);
                        visible = FALSE;
                    }
                } else {
                    if (WinQueryCapture(HWND_DESKTOP) == hwnd && !FullscreenIsNow()) {
                        WinSetCapture(HWND_DESKTOP, NULLHANDLE);
                    }

                    if (!visible && !FullscreenIsNow()) {
                        WinShowPointer(HWND_DESKTOP, TRUE);
                        visible = TRUE;
                    }

                    //
                    // don't use 'outside'-values which appears one times
                    // if the mouse pointer leaves the window
                    //
                    if (_mouse_x < 0) {
                        _mouse_x = 0;
                    } else {
                        if (_mouse_x >= swp.cx) {
                            _mouse_x = swp.cx - 1;
                        }
                    }

                    if (_mouse_y < 0) {
                       _mouse_y = 0;
                    } else {
                        if (_mouse_y >= swp.cy) {
                            _mouse_y = swp.cy - 1;
                        }
                    }
                }
            }
            return;
        case WM_BUTTON1DOWN:
            mouse_button_left(1);
            return;
        case WM_BUTTON1UP:
            mouse_button_left(0);
            return;
        case WM_BUTTON2DOWN:
            mouse_button_right(1);
            return;
        case WM_BUTTON2UP:
            mouse_button_right(0);
            return;
        case WM_BUTTON3DOWN:
            mouse_button_middle(1);
            return;
        case WM_BUTTON3UP:
            mouse_button_middle(0);
            return;
    }
}
Exemple #12
0
static void network_hook_connected_receive(void)
{
    BYTE *remote_event_buf = NULL;
    unsigned int recv_len;
    BYTE recv_len4[4];
    event_list_state_t *remote_event_list;
    event_list_state_t *client_event_list, *server_event_list;

    suspended = 0;

    if (current_frame == frame_delta - 1)
        frame_buffer_full = 1;

    if (frame_buffer_full) {
        do {
            if (network_recv_buffer(network_socket, recv_len4, 4) < 0) {
                ui_display_statustext(translate_text(IDGS_REMOTE_HOST_DISCONNECTED), 1);
                network_disconnect();
                return;
            }

            recv_len = util_le_buf4_to_int(recv_len4);
            if (recv_len == 0 && suspended == 0) {
                /* remote host suspended emulation */
                ui_display_statustext(translate_text(IDGS_REMOTE_HOST_SUSPENDING), 0);
                suspended = 1;
                vsync_suspend_speed_eval();
            }
        } while (recv_len == 0);

        if (suspended == 1)
            ui_display_statustext("", 0);

        remote_event_buf = lib_malloc(recv_len);

        if (network_recv_buffer(network_socket, remote_event_buf,
                                recv_len) < 0) {
            lib_free(remote_event_buf);
            return;
        }

#ifdef NETWORK_DEBUG
        t3 = vsyncarch_gettime();
#endif

        remote_event_list = network_create_event_list(remote_event_buf);
        lib_free(remote_event_buf);

        if (network_mode == NETWORK_SERVER_CONNECTED) {
            client_event_list = remote_event_list;
            server_event_list = &(frame_event_list[frame_to_play]);
        } else {
            server_event_list = remote_event_list;
            client_event_list = &(frame_event_list[frame_to_play]);
        }

        /* test for sync */
        if (client_event_list->base->type == EVENT_SYNC_TEST
            && server_event_list->base->type == EVENT_SYNC_TEST) {
            int i;
                
            for (i = 0; i < 5; i++) {
                if (((DWORD *)client_event_list->base->data)[i]
                    != ((DWORD *)server_event_list->base->data)[i]) {
                    ui_error(translate_text(IDGS_NETWORK_OUT_OF_SYNC));
                    network_disconnect();
                    /* shouldn't happen but resyncing would be nicer */
                    break;
                }
            }
        }

        /* replay the event_lists; server first, then client */
        event_playback_event_list(server_event_list);
        event_playback_event_list(client_event_list);

        event_clear_list(remote_event_list);
        lib_free(remote_event_list);
    }
    network_prepare_next_frame();
#ifdef NETWORK_DEBUG
    t4 = vsyncarch_gettime();
#endif
}