Exemple #1
0
static bool menu_input_key_bind_set_mode(
      enum menu_input_ctl_state state, void *data)
{
   unsigned index_offset;
   input_keyboard_ctx_wait_t keys;
   menu_handle_t       *menu = NULL;
   menu_input_t  *menu_input = menu_input_get_ptr();
   rarch_setting_t  *setting = (rarch_setting_t*)data;
   settings_t *settings      = config_get_ptr();

   if (!setting)
      return false;
   if (!menu_driver_ctl(RARCH_MENU_CTL_DRIVER_DATA_GET, &menu))
      return false;
   if (menu_input_key_bind_set_mode_common(state, setting) == -1)
      return false;

   index_offset = menu_setting_get_index_offset(setting);
   bind_port    = settings->input.joypad_map[index_offset];

   menu_input_key_bind_poll_bind_get_rested_axes(
         &menu_input->binds, bind_port);
   menu_input_key_bind_poll_bind_state(
         &menu_input->binds, bind_port, false);

   menu_input->binds.timeout_end   = cpu_features_get_time_usec() +
      MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000;

   keys.userdata = menu;
   keys.cb       = menu_input_key_bind_custom_bind_keyboard_cb;

   input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_START_WAIT_KEYS, &keys);
   return true;
}
long GetTicks(void)
{ // in MSec
#ifndef _ANDROID_

#ifdef __CELLOS_LV2__

   //#warning "GetTick PS3\n"

   unsigned long	ticks_micro;
   uint64_t secs;
   uint64_t nsecs;

   sys_time_get_current_time(&secs, &nsecs);
   ticks_micro =  secs * 1000000UL + (nsecs / 1000);

   return ticks_micro;///1000;
#elif defined(WIIU)
return (cpu_features_get_time_usec());///1000;
#else
   struct timeval tv;
   gettimeofday (&tv, NULL);
   return (tv.tv_sec*1000000 + tv.tv_usec);///1000;

#endif

#else

   struct timespec now;
   clock_gettime(CLOCK_MONOTONIC, &now);
   return (now.tv_sec*1000000 + now.tv_nsec/1000);///1000;
#endif

} 
static bool menu_input_key_bind_custom_bind_keyboard_cb(
      void *data, unsigned code)
{
   settings_t     *settings = config_get_ptr();

   menu_input_binds.target->key = (enum retro_key)code;
   menu_input_binds.begin++;
   menu_input_binds.target++;
   menu_input_binds.timeout_end = cpu_features_get_time_usec() +
      settings->input.bind_timeout * 1000000;

   return (menu_input_binds.begin <= menu_input_binds.last);
}
Exemple #4
0
static bool menu_input_key_bind_custom_bind_keyboard_cb(
      void *data, unsigned code)
{
   menu_input_t *menu_input = menu_input_get_ptr();

   if (!menu_input)
      return false;

   menu_input->binds.target->key = (enum retro_key)code;
   menu_input->binds.begin++;
   menu_input->binds.target++;
   menu_input->binds.timeout_end = cpu_features_get_time_usec() +
      MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000;

   return (menu_input->binds.begin <= menu_input->binds.last);
}
void menu_animation_update_time(bool timedate_enable)
{
   static retro_time_t
      last_clock_update     = 0;

   cur_time                 = cpu_features_get_time_usec();
   delta_time               = cur_time - old_time;

   if (delta_time >= IDEAL_DELTA_TIME* 4)
      delta_time            = IDEAL_DELTA_TIME * 4;
   if (delta_time <= IDEAL_DELTA_TIME / 4)
      delta_time            = IDEAL_DELTA_TIME / 4;
   old_time                 = cur_time;

   if (((cur_time - last_clock_update) > 1000000)
         && timedate_enable)
   {
      animation_is_active   = true;
      last_clock_update     = cur_time;
   }
}
static bool video_thread_init(thread_video_t *thr, const video_info_t *info,
      const input_driver_t **input, void **input_data)
{
   size_t max_size;
   thread_packet_t pkt = {CMD_INIT};

   thr->lock                 = slock_new();
   thr->alpha_lock           = slock_new();
   thr->frame.lock           = slock_new();
   thr->cond_cmd             = scond_new();
   thr->cond_thread          = scond_new();
   thr->input                = input;
   thr->input_data           = input_data;
   thr->info                 = *info;
   thr->alive                = true;
   thr->focus                = true;
   thr->has_windowed         = true;
   thr->suppress_screensaver = true;

   max_size                  = info->input_scale * RARCH_SCALE_BASE;
   max_size                 *= max_size;
   max_size                 *= info->rgb32 ? sizeof(uint32_t) : sizeof(uint16_t);
   thr->frame.buffer         = (uint8_t*)malloc(max_size);

   if (!thr->frame.buffer)
      return false;

   memset(thr->frame.buffer, 0x80, max_size);

   thr->last_time            = cpu_features_get_time_usec();
   thr->thread               = sthread_create(video_thread_loop, thr);

   if (!thr->thread)
      return false;

   video_thread_send_and_wait_user_to_thread(thr, &pkt);

   thr->send_and_wait        = video_thread_send_and_wait_user_to_thread;
   return pkt.data.b;
}
Exemple #7
0
/**
 * runloop_iterate:
 *
 * Run Libretro core in RetroArch for one frame.
 *
 * Returns: 0 on success, 1 if we have to wait until 
 * button input in order to wake up the loop, 
 * -1 if we forcibly quit out of the RetroArch iteration loop.
 **/
int runloop_iterate(unsigned *sleep_ms)
{
   unsigned i;
   event_cmd_state_t    cmd;
   retro_time_t current, target, to_sleep_ms;
   static retro_input_t last_input              = {0};
   event_cmd_state_t   *cmd_ptr                 = &cmd;
   static retro_time_t frame_limit_minimum_time = 0.0;
   static retro_time_t frame_limit_last_time    = 0.0;
   settings_t *settings                         = config_get_ptr();

   cmd.state[1]                                 = last_input;
   cmd.state[0]                                 = input_keys_pressed();
   last_input                                   = cmd.state[0];

   runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_TIME_LAST, NULL);

   if (runloop_ctl(RUNLOOP_CTL_SHOULD_SET_FRAME_LIMIT, NULL))
   {
      struct retro_system_av_info *av_info = 
         video_viewport_get_system_av_info();
      float fastforward_ratio              = 
         (settings->fastforward_ratio == 0.0f) 
         ? 1.0f : settings->fastforward_ratio;

      frame_limit_last_time    = cpu_features_get_time_usec();
      frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f 
            / (av_info->timing.fps * fastforward_ratio));

      runloop_ctl(RUNLOOP_CTL_UNSET_FRAME_LIMIT, NULL);
   }

   if (input_driver_is_flushing_input())
   {
      input_driver_unset_flushing_input();
      if (cmd.state[0].state)
      {
         cmd.state[0].state = 0;

         /* If core was paused before entering menu, evoke
          * pause toggle to wake it up. */
         if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL))
            BIT64_SET(cmd.state[0].state, RARCH_PAUSE_TOGGLE);
         input_driver_set_flushing_input();
      }
   }
   
   if (runloop_frame_time.callback)
   {
      /* Updates frame timing if frame timing callback is in use by the core.
       * Limits frame time if fast forward ratio throttle is enabled. */

      retro_time_t current     = cpu_features_get_time_usec();
      retro_time_t delta       = current - runloop_frame_time_last;
      bool is_locked_fps       = (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL) ||
                                  input_driver_is_nonblock_state()) |
                                  !!recording_driver_get_data_ptr();


      if (!runloop_frame_time_last || is_locked_fps)
         delta = runloop_frame_time.reference;

      if (!is_locked_fps && runloop_ctl(RUNLOOP_CTL_IS_SLOWMOTION, NULL))
         delta /= settings->slowmotion_ratio;

      runloop_frame_time_last = current;

      if (is_locked_fps)
         runloop_frame_time_last = 0;

      runloop_frame_time.callback(delta);
   }

   cmd.state[2].state      = cmd.state[0].state & ~cmd.state[1].state;  /* trigger  */

   if (runloop_cmd_triggered(cmd_ptr, RARCH_OVERLAY_NEXT))
      command_event(CMD_EVENT_OVERLAY_NEXT, NULL);

   if (runloop_cmd_triggered(cmd_ptr, RARCH_FULLSCREEN_TOGGLE_KEY))
   {
      bool fullscreen_toggled = !runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL);
#ifdef HAVE_MENU
      fullscreen_toggled = fullscreen_toggled || 
         menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL);
#endif

      if (fullscreen_toggled)
         command_event(CMD_EVENT_FULLSCREEN_TOGGLE, NULL);
   }

   if (runloop_cmd_triggered(cmd_ptr, RARCH_GRAB_MOUSE_TOGGLE))
      command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL);

#ifdef HAVE_MENU
   if (runloop_cmd_menu_press(cmd_ptr) || 
         rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
   {
      if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL))
      {
         if (rarch_ctl(RARCH_CTL_IS_INITED, NULL) && 
               !rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
            rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
      }
      else
         rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL);
   }
#endif

#ifdef HAVE_OVERLAY
   runloop_iterate_linefeed_overlay(settings);
#endif

   if (runloop_iterate_time_to_exit(
            runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1)
   {
      frame_limit_last_time = 0.0;
      return -1;
   }


#ifdef HAVE_MENU
   if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL))
   {
      int ret = runloop_iterate_menu((enum menu_action)
      menu_input_frame_retropad(cmd.state[0], cmd.state[2]),
      sleep_ms);

      if (ret == -1)
         goto end;
      return ret;
   }
#endif

   if (!runloop_check_state(&cmd, &runloop_shader_dir))
   {
      /* RetroArch has been paused. */
      core_poll();
      *sleep_ms = 10;
      return 1;
   }

#if defined(HAVE_THREADS)
   autosave_lock();
#endif

#ifdef HAVE_NETPLAY
   netplay_driver_ctl(RARCH_NETPLAY_CTL_PRE_FRAME, NULL);
#endif

   if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
      bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL);

   camera_driver_ctl(RARCH_CAMERA_CTL_POLL, NULL);

   /* Update binds for analog dpad modes. */
   for (i = 0; i < settings->input.max_users; i++)
   {
      if (!settings->input.analog_dpad_mode[i])
         continue;

      input_push_analog_dpad(settings->input.binds[i],
            settings->input.analog_dpad_mode[i]);
      input_push_analog_dpad(settings->input.autoconf_binds[i],
            settings->input.analog_dpad_mode[i]);
   }

   if ((settings->video.frame_delay > 0) && 
         !input_driver_is_nonblock_state())
      retro_sleep(settings->video.frame_delay);

   core_run();

#ifdef HAVE_CHEEVOS
   cheevos_test();
#endif

   for (i = 0; i < settings->input.max_users; i++)
   {
      if (!settings->input.analog_dpad_mode[i])
         continue;

      input_pop_analog_dpad(settings->input.binds[i]);
      input_pop_analog_dpad(settings->input.autoconf_binds[i]);
   }

   if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
      bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL);

#ifdef HAVE_NETPLAY
   netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL);
#endif

#if defined(HAVE_THREADS)
   autosave_unlock();
#endif

   if (!settings->fastforward_ratio)
      return 0;
#ifdef HAVE_MENU
end:
#endif

   current                        = cpu_features_get_time_usec();
   target                         = frame_limit_last_time + 
      frame_limit_minimum_time;
   to_sleep_ms                    = (target - current) / 1000;

   if (to_sleep_ms > 0)
   {
      *sleep_ms = (unsigned)to_sleep_ms;
      /* Combat jitter a bit. */
      frame_limit_last_time += frame_limit_minimum_time;
      return 1;
   }

   frame_limit_last_time  = cpu_features_get_time_usec();

   return 0;
}
Exemple #8
0
static bool menu_input_key_bind_iterate(char *s, size_t len)
{
   struct menu_bind_state binds;
   bool               timed_out = false;
   menu_input_t *menu_input     = menu_input_get_ptr();
   int64_t current              = cpu_features_get_time_usec();
   int timeout                  = 
      (menu_input->binds.timeout_end - current) / 1000000;

   if (timeout <= 0)
   {
      input_driver_keyboard_mapping_set_block(false);

      menu_input->binds.begin++;
      menu_input->binds.target++;
      menu_input->binds.timeout_end = cpu_features_get_time_usec() +
         MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000;
      timed_out = true;
   }

   snprintf(s, len,
         "[%s]\npress keyboard or joypad\n(timeout %d %s)",
         input_config_bind_map_get_desc(
         menu_input->binds.begin - MENU_SETTINGS_BIND_BEGIN),
         timeout,
         menu_hash_to_str(MENU_VALUE_SECONDS));

   /* binds.begin is updated in keyboard_press callback. */
   if (menu_input->binds.begin > menu_input->binds.last)
   {
      /* Avoid new binds triggering things right away. */
      input_driver_set_flushing_input();

      /* We won't be getting any key events, so just cancel early. */
      if (timed_out)
         input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_CANCEL_WAIT_KEYS, NULL);

      return true;
   }

   binds = menu_input->binds;

   input_driver_keyboard_mapping_set_block(true);
   menu_input_key_bind_poll_bind_state(&binds, bind_port, timed_out);

   if ((binds.skip && !menu_input->binds.skip) ||
         menu_input_key_bind_poll_find_trigger(&menu_input->binds, &binds))
   {
      input_driver_keyboard_mapping_set_block(false);

      /* Avoid new binds triggering things right away. */
      input_driver_set_flushing_input();

      binds.begin++;

      if (binds.begin > binds.last)
      {
         input_keyboard_ctl(RARCH_INPUT_KEYBOARD_CTL_CANCEL_WAIT_KEYS, NULL);
         return true;
      }

      binds.target++;
      binds.timeout_end = cpu_features_get_time_usec() +
         MENU_KEYBOARD_BIND_TIMEOUT_SECONDS * 1000000;
   }
   menu_input->binds = binds;

   return false;
}
Exemple #9
0
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our 
 * network buffer is full, we simply have to block 
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(void)
{
   int res;

   if (!netplay_data->has_connection)
      return false;

   netplay_data->can_poll = false;

   get_self_input_state(netplay_data);

   /* No network side in spectate mode */
   if (netplay_is_server(netplay_data) && netplay_data->spectate.enabled)
      return true;

   /* Read Netplay input, block if we're configured to stall for input every
    * frame */
   if (netplay_data->stall_frames == 0 &&
       netplay_data->read_frame_count <= netplay_data->self_frame_count)
      res = poll_input(netplay_data, true);
   else
      res = poll_input(netplay_data, false);
   if (res == -1)
   {
      hangup(netplay_data);
      return false;
   }

   /* Simulate the input if we don't have real input */
   if (!netplay_data->buffer[netplay_data->self_ptr].have_remote)
      netplay_simulate_input(netplay_data, netplay_data->self_ptr);

   /* Consider stalling */
   switch (netplay_data->stall)
   {
      case RARCH_NETPLAY_STALL_RUNNING_FAST:
         if (netplay_data->read_frame_count >= netplay_data->self_frame_count)
            netplay_data->stall = RARCH_NETPLAY_STALL_NONE;
         break;

      default: /* not stalling */
         if (netplay_data->read_frame_count + netplay_data->stall_frames 
               <= netplay_data->self_frame_count)
         {
            netplay_data->stall      = RARCH_NETPLAY_STALL_RUNNING_FAST;
            netplay_data->stall_time = cpu_features_get_time_usec();
         }
   }

   /* If we're stalling, consider disconnection */
   if (netplay_data->stall)
   {
      retro_time_t now = cpu_features_get_time_usec();

      /* Don't stall out while they're paused */
      if (netplay_data->remote_paused)
         netplay_data->stall_time = now;
      else if (now - netplay_data->stall_time >= MAX_STALL_TIME_USEC)
      {
         /* Stalled out! */
         hangup(netplay_data);
         return false;
      }
   }

   return true;
}
Exemple #10
0
int net_http_get(const char **result, size_t *size, const char *url, retro_time_t *timeout)
{
   size_t length;
   uint8_t* data                  = NULL;
   char* res                      = NULL;
   int ret                        = NET_HTTP_GET_OK;
   struct http_t* http            = NULL;
   retro_time_t t0                = cpu_features_get_time_usec();
   struct http_connection_t *conn = net_http_connection_new(url);

   *result = NULL;

   /* Error creating the connection descriptor. */
   if (!conn)
      goto error;

   /* Don't bother with timeouts here, it's just a string scan. */
   while (!net_http_connection_iterate(conn)) {}

   /* Error finishing the connection descriptor. */
   if (!net_http_connection_done(conn))
   {
      ret = NET_HTTP_GET_MALFORMED_URL;
      goto error;
   }

   http = net_http_new(conn);

   /* Error connecting to the endpoint. */
   if (!http)
   {
      ret = NET_HTTP_GET_CONNECT_ERROR;
      goto error;
   }

   while (!net_http_update(http, NULL, NULL))
   {
      /* Timeout error. */
      if (timeout && (cpu_features_get_time_usec() - t0) > *timeout)
      {
         ret = NET_HTTP_GET_TIMEOUT;
         goto error;
      }
   }

   data = net_http_data(http, &length, false);

   if (data)
   {
      res = (char*)malloc(length + 1);

      /* Allocation error. */
      if ( !res )
         goto error;

      memcpy((void*)res, (void*)data, length);
      free(data);
      res[length] = 0;
      *result = res;
   }
   else
   {
      length = 0;
      *result = NULL;
   }

   if (size)
      *size = length;

error:
   if ( http )
      net_http_delete( http );

   if ( conn )
      net_http_connection_free( conn );

   if (timeout)
   {
      t0 = cpu_features_get_time_usec() - t0;

      if (t0 < *timeout)
         *timeout -= t0;
      else
         *timeout = 0;
   }

   return ret;
}
Exemple #11
0
/**
 * netplay_sync_post_frame
 * @netplay              : pointer to netplay object
 *
 * Post-frame for Netplay synchronization.
 * We check if we have new input and replay from recorded input.
 */
void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
{
   uint32_t lo_frame_count, hi_frame_count;

   /* Unless we're stalling, we've just finished running a frame */
   if (!stalled)
   {
      netplay->run_ptr = NEXT_PTR(netplay->run_ptr);
      netplay->run_frame_count++;
   }

   /* We've finished an input frame even if we're stalling */
   if ((!stalled || netplay->stall == NETPLAY_STALL_INPUT_LATENCY) &&
       netplay->self_frame_count < netplay->run_frame_count + netplay->input_latency_frames)
   {
      netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
      netplay->self_frame_count++;
   }

   /* Only relevant if we're connected and not in a desynching operation */
   if ((netplay->is_server && !netplay->connected_players) ||
       (netplay->self_mode < NETPLAY_CONNECTION_CONNECTED) ||
       (netplay->desync))
   {
      netplay->other_frame_count = netplay->self_frame_count;
      netplay->other_ptr = netplay->self_ptr;
      /* FIXME: Duplication */
      if (netplay->catch_up)
      {
         netplay->catch_up = false;
         input_driver_unset_nonblock_state();
         driver_set_nonblock_state();
      }
      return;
   }

   /* Reset if it was requested */
   if (netplay->force_reset)
   {
      core_reset();
      netplay->force_reset = false;
   }

#ifndef DEBUG_NONDETERMINISTIC_CORES
   if (!netplay->force_rewind)
   {
      /* Skip ahead if we predicted correctly.
       * Skip until our simulation failed. */
      while (netplay->other_frame_count < netplay->unread_frame_count &&
             netplay->other_frame_count < netplay->run_frame_count)
      {
         struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr];
         size_t i;

         for (i = 0; i < MAX_USERS; i++)
         {
            if (memcmp(ptr->simulated_input_state[i], ptr->real_input_state[i],
                     sizeof(ptr->real_input_state[i])) != 0
                  && !ptr->used_real[i])
               break;
         }
         if (i != MAX_USERS) break;
         netplay_handle_frame_hash(netplay, ptr);
         netplay->other_ptr = NEXT_PTR(netplay->other_ptr);
         netplay->other_frame_count++;
      }
   }
#endif

   /* Now replay the real input if we've gotten ahead of it */
   if (netplay->force_rewind ||
       (netplay->other_frame_count < netplay->unread_frame_count &&
        netplay->other_frame_count < netplay->run_frame_count))
   {
      retro_ctx_serialize_info_t serial_info;

      /* Replay frames. */
      netplay->is_replay = true;
      netplay->replay_ptr = netplay->other_ptr;
      netplay->replay_frame_count = netplay->other_frame_count;

      if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
         /* Make sure we're initialized before we start loading things */
         netplay_wait_and_init_serialization(netplay);

      serial_info.data       = NULL;
      serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
      serial_info.size       = netplay->state_size;

      if (!core_unserialize(&serial_info))
      {
         RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n");
      }

      while (netplay->replay_frame_count < netplay->run_frame_count)
      {
         retro_time_t start, tm;

         struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr];
         serial_info.data       = ptr->state;
         serial_info.size       = netplay->state_size;
         serial_info.data_const = NULL;

         start = cpu_features_get_time_usec();

         /* Remember the current state */
         memset(serial_info.data, 0, serial_info.size);
         core_serialize(&serial_info);
         if (netplay->replay_frame_count < netplay->unread_frame_count)
            netplay_handle_frame_hash(netplay, ptr);

         /* Re-simulate this frame's input */
         netplay_simulate_input(netplay, netplay->replay_ptr, true);

         autosave_lock();
         core_run();
         autosave_unlock();
         netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr);
         netplay->replay_frame_count++;

#ifdef DEBUG_NONDETERMINISTIC_CORES
         if (ptr->have_remote && netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->replay_ptr], netplay->replay_frame_count))
         {
            RARCH_LOG("PRE  %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr));
            if (netplay->is_server)
               RARCH_LOG("INP  %X %X\n", ptr->real_input_state[0], ptr->self_state[0]);
            else
               RARCH_LOG("INP  %X %X\n", ptr->self_state[0], ptr->real_input_state[0]);
            ptr = &netplay->buffer[netplay->replay_ptr];
            serial_info.data = ptr->state;
            memset(serial_info.data, 0, serial_info.size);
            core_serialize(&serial_info);
            RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr));
         }
#endif

         /* Get our time window */
         tm = cpu_features_get_time_usec() - start;
         netplay->frame_run_time_sum -= netplay->frame_run_time[netplay->frame_run_time_ptr];
         netplay->frame_run_time[netplay->frame_run_time_ptr] = tm;
         netplay->frame_run_time_sum += tm;
         netplay->frame_run_time_ptr++;
         if (netplay->frame_run_time_ptr >= NETPLAY_FRAME_RUN_TIME_WINDOW)
            netplay->frame_run_time_ptr = 0;
      }

      /* Average our time */
      netplay->frame_run_time_avg = netplay->frame_run_time_sum / NETPLAY_FRAME_RUN_TIME_WINDOW;

      if (netplay->unread_frame_count < netplay->run_frame_count)
      {
         netplay->other_ptr = netplay->unread_ptr;
         netplay->other_frame_count = netplay->unread_frame_count;
      }
      else
      {
         netplay->other_ptr = netplay->run_ptr;
         netplay->other_frame_count = netplay->run_frame_count;
      }
      netplay->is_replay = false;
      netplay->force_rewind = false;
   }

   if (netplay->is_server)
   {
      uint32_t player;

      lo_frame_count = hi_frame_count = netplay->unread_frame_count;

      /* Look for players that are ahead of us */
      for (player = 0; player < MAX_USERS; player++)
      {
         if (!(netplay->connected_players & (1<<player))) continue;
         if (netplay->read_frame_count[player] > hi_frame_count)
            hi_frame_count = netplay->read_frame_count[player];
      }
   }
   else
   {
      lo_frame_count = hi_frame_count = netplay->server_frame_count;
   }

   /* If we're behind, try to catch up */
   if (netplay->catch_up)
   {
      /* Are we caught up? */
      if (netplay->self_frame_count + 1 >= lo_frame_count)
      {
         netplay->catch_up = false;
         input_driver_unset_nonblock_state();
         driver_set_nonblock_state();
      }

   }
   else if (!stalled)
   {
      if (netplay->self_frame_count + 3 < lo_frame_count)
      {
         retro_time_t cur_time = cpu_features_get_time_usec();
         uint32_t cur_behind = lo_frame_count - netplay->self_frame_count;

         /* We're behind, but we'll only try to catch up if we're actually
          * falling behind, i.e. if we're more behind after some time */
         if (netplay->catch_up_time == 0)
         {
            /* Record our current time to check for catch-up later */
            netplay->catch_up_time = cur_time;
            netplay->catch_up_behind = cur_behind;

         }
         else if (cur_time - netplay->catch_up_time > CATCH_UP_CHECK_TIME_USEC)
         {
            /* Time to check how far behind we are */
            if (netplay->catch_up_behind <= cur_behind)
            {
               /* We're definitely falling behind! */
               netplay->catch_up = true;
               netplay->catch_up_time = 0;
               input_driver_set_nonblock_state();
               driver_set_nonblock_state();
            }
            else
            {
               /* Check again in another period */
               netplay->catch_up_time = cur_time;
               netplay->catch_up_behind = cur_behind;
            }
         }

      }
      else if (netplay->self_frame_count + 3 < hi_frame_count)
      {
         size_t i;
         netplay->catch_up_time = 0;

         /* We're falling behind some clients but not others, so request that
          * clients ahead of us stall */
         for (i = 0; i < netplay->connections_size; i++)
         {
            struct netplay_connection *connection = &netplay->connections[i];
            int player;
            if (!connection->active ||
                connection->mode != NETPLAY_CONNECTION_PLAYING)
               continue;
            player = connection->player;

            /* Are they ahead? */
            if (netplay->self_frame_count + 3 < netplay->read_frame_count[player])
            {
               /* Tell them to stall */
               if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY <
                     netplay->self_frame_count)
               {
                  connection->stall_frame = netplay->self_frame_count;
                  netplay_cmd_stall(netplay, connection,
                     netplay->read_frame_count[player] -
                     netplay->self_frame_count + 1);
               }
            }
         }
      }
      else
         netplay->catch_up_time = 0;
   }
   else
      netplay->catch_up_time =  0;
}
bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data)
{
   static menu_animation_t anim;
   static retro_time_t cur_time    = 0;
   static retro_time_t old_time    = 0;
   static float delta_time         = 0.0f;
   static bool animation_is_active = false;

   switch (state)
   {
      case MENU_ANIMATION_CTL_DEINIT:
         {
            size_t i;

            for (i = 0; i < anim.size; i++)
            {
               if (anim.list[i].subject)
                  anim.list[i].subject = NULL;
            }

            free(anim.list);

            memset(&anim, 0, sizeof(menu_animation_t));
         }
         cur_time                  = 0;
         old_time                  = 0;
         delta_time                = 0.0f;
         break;
      case MENU_ANIMATION_CTL_IS_ACTIVE:
         return animation_is_active;
      case MENU_ANIMATION_CTL_CLEAR_ACTIVE:
         animation_is_active       = false;
         break;
      case MENU_ANIMATION_CTL_SET_ACTIVE:
         animation_is_active       = true;
         break;
      case MENU_ANIMATION_CTL_DELTA_TIME:
         {
            float *ptr = (float*)data;
            if (!ptr)
               return false;
            *ptr = delta_time;
         }
         break;
      case MENU_ANIMATION_CTL_UPDATE_TIME:
         {
            static retro_time_t last_clock_update = 0;
            settings_t *settings     = config_get_ptr();

            cur_time                 = cpu_features_get_time_usec();
            delta_time               = cur_time - old_time;

            if (delta_time >= IDEAL_DELTA_TIME* 4)
               delta_time = IDEAL_DELTA_TIME * 4;
            if (delta_time <= IDEAL_DELTA_TIME / 4)
               delta_time = IDEAL_DELTA_TIME / 4;
            old_time      = cur_time;

            if (((cur_time - last_clock_update) > 1000000) 
                  && settings->menu.timedate_enable)
            {
               animation_is_active   = true;
               last_clock_update     = cur_time;
            }
         }
         break;
      case MENU_ANIMATION_CTL_UPDATE:
         {
            unsigned i;
            unsigned active_tweens = 0;
            float *dt = (float*)data;

            if (!dt)
               return false;

            for(i = 0; i < anim.size; i++)
               menu_animation_iterate(&anim, i, *dt, &active_tweens);

            if (!active_tweens)
            {
               anim.size       = 0;
               anim.first_dead = 0;
               return false;
            }

            animation_is_active = true;
         }
         break;
      case MENU_ANIMATION_CTL_KILL_BY_TAG:
         {
            unsigned i;
            menu_animation_ctx_tag_t *tag = (menu_animation_ctx_tag_t*)data;

            if (!tag || tag->id == -1)
               return false;

            for (i = 0; i < anim.size; ++i)
            {
               if (anim.list[i].tag != tag->id)
                  continue;

               anim.list[i].alive   = false;
               anim.list[i].subject = NULL;

               if (i < anim.first_dead)
                  anim.first_dead = i;
            }
         }
         break;
      case MENU_ANIMATION_CTL_KILL_BY_SUBJECT:
         {
            unsigned i, j,  killed = 0;
            menu_animation_ctx_subject_t *subject = 
               (menu_animation_ctx_subject_t*)data;
            float            **sub = (float**)subject->data;

            for (i = 0; i < anim.size; ++i)
            {
               if (!anim.list[i].alive)
                  continue;

               for (j = 0; j < subject->count; ++j)
               {
                  if (anim.list[i].subject != sub[j])
                     continue;

                  anim.list[i].alive   = false;
                  anim.list[i].subject = NULL;

                  if (i < anim.first_dead)
                     anim.first_dead = i;

                  killed++;
                  break;
               }
            }
         }
         break;
      case MENU_ANIMATION_CTL_TICKER:
         {
            menu_animation_ctx_ticker_t *ticker = (menu_animation_ctx_ticker_t*)
               data;
            size_t           str_len = utf8len(ticker->str);
            size_t           offset  = 0;

            if ((size_t)str_len <= ticker->len)
            {
               utf8cpy(ticker->s,
                     PATH_MAX_LENGTH,
                     ticker->str,
                     ticker->len);
               return true;
            }

            if (!ticker->selected)
            {
               utf8cpy(ticker->s, PATH_MAX_LENGTH, ticker->str, ticker->len - 3);
               strlcat(ticker->s, "...", PATH_MAX_LENGTH);
               return true;
            }

            menu_animation_ticker_generic(
                  ticker->idx,
                  ticker->len,
                  &offset,
                  &str_len);

            utf8cpy(
                  ticker->s,
                  PATH_MAX_LENGTH,
                  utf8skip(ticker->str, offset),
                  str_len);

            animation_is_active = true;
         }
         break;
      case MENU_ANIMATION_CTL_IDEAL_DELTA_TIME_GET:
         {
            menu_animation_ctx_delta_t *delta = 
               (menu_animation_ctx_delta_t*)data;
            if (!delta)
               return false;
            delta->ideal = delta->current / IDEAL_DELTA_TIME;
         }
         break;
      case MENU_ANIMATION_CTL_PUSH:
         return menu_animation_push(&anim, data);
      case MENU_ANIMATION_CTL_NONE:
      default:
         break;
   }

   return true;
}
Exemple #13
0
int menu_popup_iterate(char *s, size_t len, const char *label)
{
#ifdef HAVE_CHEEVOS
   cheevos_ctx_desc_t desc_info;
#endif
   bool do_exit              = false;
   settings_t *settings      = config_get_ptr();

   switch (menu_popup_current_type)
   {
      case MENU_POPUP_WELCOME:
         {
            static int64_t timeout_end;
            int64_t timeout;
            static bool timer_begin = false;
            static bool timer_end   = false;
            int64_t current         = cpu_features_get_time_usec();

            if (!timer_begin)
            {
               timeout_end = cpu_features_get_time_usec() +
                  3 /* seconds */ * 1000000;
               timer_begin = true;
               timer_end   = false;
            }

            timeout = (timeout_end - current) / 1000000;

            menu_hash_get_help_enum(
                  MENU_ENUM_LABEL_WELCOME_TO_RETROARCH,
                  s, len);

            if (!timer_end && timeout <= 0)
            {
               timer_end   = true;
               timer_begin = false;
               timeout_end = 0;
               do_exit     = true;
            }
         }
         break;
      case MENU_POPUP_HELP_CONTROLS:
         {
            unsigned i;
            char s2[PATH_MAX_LENGTH] = {0};
            const unsigned binds[] = {
               RETRO_DEVICE_ID_JOYPAD_UP,
               RETRO_DEVICE_ID_JOYPAD_DOWN,
               RETRO_DEVICE_ID_JOYPAD_A,
               RETRO_DEVICE_ID_JOYPAD_B,
               RETRO_DEVICE_ID_JOYPAD_SELECT,
               RETRO_DEVICE_ID_JOYPAD_START,
               RARCH_MENU_TOGGLE,
               RARCH_QUIT_KEY,
               RETRO_DEVICE_ID_JOYPAD_X,
               RETRO_DEVICE_ID_JOYPAD_Y,
            };
            char desc[ARRAY_SIZE(binds)][64] = {{0}};

            for (i = 0; i < ARRAY_SIZE(binds); i++)
            {
               const struct retro_keybind *keybind =
                  (const struct retro_keybind*)
                  &settings->input.binds[0][binds[i]];
               const struct retro_keybind *auto_bind =
                  (const struct retro_keybind*)
                  input_get_auto_bind(0, binds[i]);

               input_config_get_bind_string(desc[i],
                     keybind, auto_bind, sizeof(desc[i]));
            }

            menu_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG,
                  s2, sizeof(s2));

            snprintf(s, len,
                  "%s"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n"
                  "[%s]: "
                  "%-20s\n",

                  s2,

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP),
                  desc[0],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN),
                  desc[1],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM),
                  desc[2],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK),
                  desc[3],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO),
                  desc[4],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START),
                  desc[5],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU),
                  desc[6],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT),
                  desc[7],

                  msg_hash_to_str(
                        MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD),
                  desc[8]

                  );
         }
         break;

#ifdef HAVE_CHEEVOS
      case MENU_POPUP_HELP_CHEEVOS_DESCRIPTION:
         desc_info.idx = menu_popup_current_id;
         desc_info.s   = s;
         desc_info.len = len;
         cheevos_get_description(&desc_info);
         break;
#endif

      case MENU_POPUP_HELP_WHAT_IS_A_CORE:
         menu_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC,
               s, len);
         break;
      case MENU_POPUP_HELP_LOADING_CONTENT:
         menu_hash_get_help_enum(MENU_ENUM_LABEL_LOAD_CONTENT_LIST,
               s, len);
         break;
      case MENU_POPUP_HELP_CHANGE_VIRTUAL_GAMEPAD:
         menu_hash_get_help_enum(
               MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC,
               s, len);
         break;
      case MENU_POPUP_HELP_AUDIO_VIDEO_TROUBLESHOOTING:
         menu_hash_get_help_enum(
               MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC,
               s, len);
         break;
      case MENU_POPUP_HELP_SCANNING_CONTENT:
         menu_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC,
               s, len);
         break;
      case MENU_POPUP_HELP_EXTRACT:
         menu_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT,
               s, len);

         if (settings->bundle_finished)
         {
            settings->bundle_finished = false;
            do_exit                   = true;
         }
         break;
      case MENU_POPUP_QUIT_CONFIRM:
      case MENU_POPUP_INFORMATION:
      case MENU_POPUP_QUESTION:
      case MENU_POPUP_WARNING:
      case MENU_POPUP_ERROR:
         menu_hash_get_help_enum(menu_popup_current_msg,
               s, len);
         break;
      case MENU_POPUP_NONE:
      default:
         break;
   }

   if (do_exit)
   {
      menu_popup_current_type = MENU_POPUP_NONE;
      return 1;
   }

   return 0;
}
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our
 * network buffer is full, we simply have to block
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(void)
{
   int res;
   uint32_t client;
   size_t i;

   netplay_data->can_poll = false;

   if (!get_self_input_state(netplay_data))
      goto catastrophe;

   /* If we're not connected, we're done */
   if (netplay_data->self_mode == NETPLAY_CONNECTION_NONE)
      return true;

   /* Read Netplay input, block if we're configured to stall for input every
    * frame */
   netplay_update_unread_ptr(netplay_data);
   if (netplay_data->stateless_mode &&
       (netplay_data->connected_players>1) &&
       netplay_data->unread_frame_count <= netplay_data->run_frame_count)
      res = netplay_poll_net_input(netplay_data, true);
   else
      res = netplay_poll_net_input(netplay_data, false);
   if (res == -1)
      goto catastrophe;

   /* Resolve and/or simulate the input if we don't have real input */
   netplay_resolve_input(netplay_data, netplay_data->run_ptr, false);

   /* Handle any slaves */
   if (netplay_data->is_server && netplay_data->connected_slaves)
      netplay_handle_slaves(netplay_data);

   netplay_update_unread_ptr(netplay_data);

   /* Figure out how many frames of input latency we should be using to hide
    * network latency */
   if (netplay_data->frame_run_time_avg || netplay_data->stateless_mode)
   {
      /* FIXME: Using fixed 60fps for this calculation */
      unsigned frames_per_frame = netplay_data->frame_run_time_avg ?
                                  (16666/netplay_data->frame_run_time_avg) :
                                   0;
      unsigned frames_ahead = (netplay_data->run_frame_count > netplay_data->unread_frame_count) ?
                              (netplay_data->run_frame_count - netplay_data->unread_frame_count) :
                              0;
      settings_t *settings  = config_get_ptr();
      unsigned input_latency_frames_min = settings->uints.netplay_input_latency_frames_min;
      unsigned input_latency_frames_max = input_latency_frames_min + settings->uints.netplay_input_latency_frames_range;

      /* Assume we need a couple frames worth of time to actually run the
       * current frame */
      if (frames_per_frame > 2)
         frames_per_frame -= 2;
      else
         frames_per_frame = 0;

      /* Shall we adjust our latency? */
      if (netplay_data->stateless_mode)
      {
         /* In stateless mode, we adjust up if we're "close" and down if we
          * have a lot of slack */
         if (netplay_data->input_latency_frames < input_latency_frames_min ||
             (netplay_data->unread_frame_count == netplay_data->run_frame_count + 1 &&
              netplay_data->input_latency_frames < input_latency_frames_max))
         {
            netplay_data->input_latency_frames++;
         }
         else if (netplay_data->input_latency_frames > input_latency_frames_max ||
                  (netplay_data->unread_frame_count > netplay_data->run_frame_count + 2 &&
                   netplay_data->input_latency_frames > input_latency_frames_min))
         {
            netplay_data->input_latency_frames--;
         }

      }
      else if (netplay_data->input_latency_frames < input_latency_frames_min ||
               (frames_per_frame < frames_ahead &&
                netplay_data->input_latency_frames < input_latency_frames_max))
      {
         /* We can't hide this much network latency with replay, so hide some
          * with input latency */
         netplay_data->input_latency_frames++;
      }
      else if (netplay_data->input_latency_frames > input_latency_frames_max ||
               (frames_per_frame > frames_ahead + 2 &&
                netplay_data->input_latency_frames > input_latency_frames_min))
      {
         /* We don't need this much latency (any more) */
         netplay_data->input_latency_frames--;
      }
   }

   /* If we're stalled, consider unstalling */
   switch (netplay_data->stall)
   {
      case NETPLAY_STALL_RUNNING_FAST:
      {
         if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
               > netplay_data->self_frame_count)
         {
            netplay_data->stall = NETPLAY_STALL_NONE;
            for (i = 0; i < netplay_data->connections_size; i++)
            {
               struct netplay_connection *connection = &netplay_data->connections[i];
               if (connection->active && connection->stall)
                  connection->stall = NETPLAY_STALL_NONE;
            }
         }
         break;
      }

      case NETPLAY_STALL_SPECTATOR_WAIT:
         if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING || netplay_data->unread_frame_count > netplay_data->self_frame_count)
            netplay_data->stall = NETPLAY_STALL_NONE;
         break;

      case NETPLAY_STALL_INPUT_LATENCY:
         /* Just let it recalculate momentarily */
         netplay_data->stall = NETPLAY_STALL_NONE;
         break;

      case NETPLAY_STALL_SERVER_REQUESTED:
      {
         /* See if the stall is done */
         if (netplay_data->connections[0].stall_frame == 0)
         {
            /* Stop stalling! */
            netplay_data->connections[0].stall = NETPLAY_STALL_NONE;
            netplay_data->stall = NETPLAY_STALL_NONE;
         }
         else
         {
            netplay_data->connections[0].stall_frame--;
         }
         break;
      }

      case NETPLAY_STALL_NO_CONNECTION:
         /* We certainly haven't fixed this */
         break;

      default: /* not stalling */
         break;
   }

   /* If we're not stalled, consider stalling */
   if (!netplay_data->stall)
   {
      /* Have we not read enough latency frames? */
      if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING &&
          netplay_data->connected_players &&
          netplay_data->run_frame_count + netplay_data->input_latency_frames > netplay_data->self_frame_count)
      {
         netplay_data->stall = NETPLAY_STALL_INPUT_LATENCY;
         netplay_data->stall_time = 0;
      }

      /* Are we too far ahead? */
      if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
            <= netplay_data->self_frame_count)
      {
         netplay_data->stall      = NETPLAY_STALL_RUNNING_FAST;
         netplay_data->stall_time = cpu_features_get_time_usec();

         /* Figure out who to blame */
         if (netplay_data->is_server)
         {
            for (client = 1; client < MAX_CLIENTS; client++)
            {
               struct netplay_connection *connection;
               if (!(netplay_data->connected_players & (1<<client)))
                  continue;
               if (netplay_data->read_frame_count[client] > netplay_data->unread_frame_count)
                  continue;
               connection = &netplay_data->connections[client-1];
               if (connection->active &&
                   connection->mode == NETPLAY_CONNECTION_PLAYING)
               {
                  connection->stall = NETPLAY_STALL_RUNNING_FAST;
                  connection->stall_time = netplay_data->stall_time;
               }
            }
         }

      }

      /* If we're a spectator, are we ahead at all? */
      if (!netplay_data->is_server &&
          (netplay_data->self_mode == NETPLAY_CONNECTION_SPECTATING ||
           netplay_data->self_mode == NETPLAY_CONNECTION_SLAVE) &&
          netplay_data->unread_frame_count <= netplay_data->self_frame_count)
      {
         netplay_data->stall = NETPLAY_STALL_SPECTATOR_WAIT;
         netplay_data->stall_time = cpu_features_get_time_usec();
      }
   }

   /* If we're stalling, consider disconnection */
   if (netplay_data->stall && netplay_data->stall_time)
   {
      retro_time_t now = cpu_features_get_time_usec();

      /* Don't stall out while they're paused */
      if (netplay_data->remote_paused)
         netplay_data->stall_time = now;
      else if (now - netplay_data->stall_time >=
               (netplay_data->is_server ? MAX_SERVER_STALL_TIME_USEC :
                                          MAX_CLIENT_STALL_TIME_USEC))
      {
         /* Stalled out! */
         if (netplay_data->is_server)
         {
            for (i = 0; i < netplay_data->connections_size; i++)
            {
               struct netplay_connection *connection = &netplay_data->connections[i];
               if (connection->active &&
                   connection->mode == NETPLAY_CONNECTION_PLAYING &&
                   connection->stall &&
                   now - connection->stall_time >= MAX_SERVER_STALL_TIME_USEC)
               {
                  netplay_hangup(netplay_data, connection);
               }
            }
         }
         else
            goto catastrophe;
         return false;
      }
   }

   return true;

catastrophe:
   for (i = 0; i < netplay_data->connections_size; i++)
      netplay_hangup(netplay_data, &netplay_data->connections[i]);
   return false;
}
static bool video_thread_frame(void *data, const void *frame_,
      unsigned width, unsigned height, uint64_t frame_count,
      unsigned pitch, const char *msg)
{
   unsigned copy_stride;
   static struct retro_perf_counter thr_frame = {0};
   const uint8_t *src                  = NULL;
   uint8_t *dst                        = NULL;
   thread_video_t *thr                 = (thread_video_t*)data;

   /* If called from within read_viewport, we're actually in the 
    * driver thread, so just render directly. */
   if (thr->frame.within_thread)
   {
      thread_update_driver_state(thr);

      if (thr->driver && thr->driver->frame)
         return thr->driver->frame(thr->driver_data, frame_,
               width, height, frame_count, pitch, msg);
      return false;
   }

   performance_counter_init(&thr_frame, "thr_frame");
   performance_counter_start(&thr_frame);

   copy_stride = width * (thr->info.rgb32 
         ? sizeof(uint32_t) : sizeof(uint16_t));

   src = (const uint8_t*)frame_;
   dst = thr->frame.buffer;

   slock_lock(thr->lock);

   if (!thr->nonblock)
   {
      settings_t *settings = config_get_ptr();

      retro_time_t target_frame_time = (retro_time_t)
         roundf(1000000 / settings->video.refresh_rate);
      retro_time_t target = thr->last_time + target_frame_time;

      /* Ideally, use absolute time, but that is only a good idea on POSIX. */
      while (thr->frame.updated)
      {
         retro_time_t current = cpu_features_get_time_usec();
         retro_time_t delta   = target - current;

         if (delta <= 0)
            break;

         if (!scond_wait_timeout(thr->cond_cmd, thr->lock, delta))
            break;
      }
   }

   /* Drop frame if updated flag is still set, as thread is 
    * still working on last frame. */
   if (!thr->frame.updated)
   {
      if (src)
      {
         unsigned h;
         for (h = 0; h < height; h++, src += pitch, dst += copy_stride)
            memcpy(dst, src, copy_stride);
      }

      thr->frame.updated = true;
      thr->frame.width  = width;
      thr->frame.height = height;
      thr->frame.count  = frame_count;
      thr->frame.pitch  = copy_stride;

      if (msg)
         strlcpy(thr->frame.msg, msg, sizeof(thr->frame.msg));
      else
         *thr->frame.msg = '\0';

      scond_signal(thr->cond_thread);

#if defined(HAVE_MENU)
      if (thr->texture.enable)
      {
         while (thr->frame.updated)
            scond_wait(thr->cond_cmd, thr->lock);
      }
#endif
      thr->hit_count++;
   }
   else
      thr->miss_count++;

   slock_unlock(thr->lock);

   performance_counter_stop(&thr_frame);

   thr->last_time = cpu_features_get_time_usec();
   return true;
}
Exemple #16
0
/**
 * runloop_iterate:
 *
 * Run Libretro core in RetroArch for one frame.
 *
 * Returns: 0 on success, 1 if we have to wait until
 * button input in order to wake up the loop,
 * -1 if we forcibly quit out of the RetroArch iteration loop.
 **/
int runloop_iterate(unsigned *sleep_ms)
{
   unsigned i;
   retro_time_t current, target, to_sleep_ms;
   static uint64_t last_input                   = 0;
   enum runloop_state runloop_status            = RUNLOOP_STATE_NONE;
   static retro_time_t frame_limit_minimum_time = 0.0;
   static retro_time_t frame_limit_last_time    = 0.0;
   settings_t *settings                         = config_get_ptr();
   uint64_t current_input                       = menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL) ? input_menu_keys_pressed() : input_keys_pressed();
   uint64_t old_input                           = last_input;

   last_input                                   = current_input;

   if (runloop_frame_time_last_enable)
   {
      runloop_frame_time_last        = 0;
      runloop_frame_time_last_enable = false;
   }

   if (runloop_set_frame_limit)
   {
      struct retro_system_av_info *av_info =
         video_viewport_get_system_av_info();
      float fastforward_ratio              =
         (settings->fastforward_ratio == 0.0f)
         ? 1.0f : settings->fastforward_ratio;

      frame_limit_last_time    = cpu_features_get_time_usec();
      frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f
            / (av_info->timing.fps * fastforward_ratio));

      runloop_set_frame_limit = false;
   }

   if (runloop_frame_time.callback)
   {
      /* Updates frame timing if frame timing callback is in use by the core.
       * Limits frame time if fast forward ratio throttle is enabled. */

      retro_time_t current     = cpu_features_get_time_usec();
      retro_time_t delta       = current - runloop_frame_time_last;
      bool is_locked_fps       = (runloop_paused ||
                                  input_driver_is_nonblock_state()) |
                                  !!recording_driver_get_data_ptr();


      if (!runloop_frame_time_last || is_locked_fps)
         delta = runloop_frame_time.reference;

      if (!is_locked_fps && runloop_slowmotion)
         delta /= settings->slowmotion_ratio;

      runloop_frame_time_last = current;

      if (is_locked_fps)
         runloop_frame_time_last = 0;

      runloop_frame_time.callback(delta);
   }

   runloop_status = runloop_check_state(settings, current_input,
         old_input, sleep_ms);

   switch (runloop_status)
   {
      case RUNLOOP_STATE_QUIT:
         frame_limit_last_time = 0.0;
         command_event(CMD_EVENT_QUIT, NULL);
         return -1;
      case RUNLOOP_STATE_SLEEP:
      case RUNLOOP_STATE_END:
      case RUNLOOP_STATE_MENU_ITERATE:
         core_poll();
#ifdef HAVE_NETWORKING
         /* FIXME: This is an ugly way to tell Netplay this... */
         netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
#endif
         if (runloop_status == RUNLOOP_STATE_SLEEP)
            *sleep_ms = 10;
         if (runloop_status == RUNLOOP_STATE_END)
            goto end;
         if (runloop_status == RUNLOOP_STATE_MENU_ITERATE)
            return 0;
         return 1;
      case RUNLOOP_STATE_ITERATE:
      case RUNLOOP_STATE_NONE:
      default:
         break;
   }

   autosave_lock();

   if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
      bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_START, NULL);

   camera_driver_ctl(RARCH_CAMERA_CTL_POLL, NULL);

   /* Update binds for analog dpad modes. */
   for (i = 0; i < settings->input.max_users; i++)
   {
      if (!settings->input.analog_dpad_mode[i])
         continue;

      input_push_analog_dpad(settings->input.binds[i],
            settings->input.analog_dpad_mode[i]);
      input_push_analog_dpad(settings->input.autoconf_binds[i],
            settings->input.analog_dpad_mode[i]);
   }

   if ((settings->video.frame_delay > 0) &&
         !input_driver_is_nonblock_state())
      retro_sleep(settings->video.frame_delay);

   core_run();

#ifdef HAVE_CHEEVOS
   cheevos_test();
#endif

   for (i = 0; i < settings->input.max_users; i++)
   {
      if (!settings->input.analog_dpad_mode[i])
         continue;

      input_pop_analog_dpad(settings->input.binds[i]);
      input_pop_analog_dpad(settings->input.autoconf_binds[i]);
   }

   if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
      bsv_movie_ctl(BSV_MOVIE_CTL_SET_FRAME_END, NULL);

   autosave_unlock();

   if (!settings->fastforward_ratio)
      return 0;

end:

   current                        = cpu_features_get_time_usec();
   target                         = frame_limit_last_time +
      frame_limit_minimum_time;
   to_sleep_ms                    = (target - current) / 1000;

   if (to_sleep_ms > 0)
   {
      *sleep_ms = (unsigned)to_sleep_ms;
      /* Combat jitter a bit. */
      frame_limit_last_time += frame_limit_minimum_time;
      return 1;
   }

   frame_limit_last_time  = cpu_features_get_time_usec();

   return 0;
}