Beispiel #1
0
void VideoBackendHardware::Video_ExitLoop()
{
	ExitGpuLoop();
	s_FifoShuttingDown.Set();
	s_efbAccessReadyEvent.Set();
	s_perfQueryReadyEvent.Set();
}
Beispiel #2
0
void DSPLLE::DSP_StopSoundStream()
{
	if (m_bDSPThread)
	{
		m_bIsRunning.Clear();
		ppcEvent.Set();
		dspEvent.Set();
		m_hDSPThread.join();
	}
}
Beispiel #3
0
void DSPLLE::DSP_StopSoundStream()
{
	DSPInterpreter::Stop();
	m_bIsRunning = false;
	if (m_bDSPThread)
	{
		ppcEvent.Set();
		dspEvent.Set();
		m_hDSPThread.join();
	}
}
Beispiel #4
0
static void DVDThread()
{
  Common::SetCurrentThreadName("DVD thread");

  while (true)
  {
    s_request_queue_expanded.Wait();

    if (s_dvd_thread_exiting.IsSet())
      return;

    ReadRequest request;
    while (s_request_queue.Pop(request))
    {
      FileMonitor::Log(*s_disc, request.partition, request.dvd_offset);

      std::vector<u8> buffer(request.length);
      if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
        buffer.resize(0);

      request.realtime_done_us = Common::Timer::GetTimeUs();

      s_result_queue.Push(ReadResult(std::move(request), std::move(buffer)));
      s_result_queue_expanded.Set();

      if (s_dvd_thread_exiting.IsSet())
        return;
    }
  }
}
Beispiel #5
0
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
                              const DiscIO::Partition& partition,
                              DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
{
  ASSERT(Core::IsCPUThread());

  ReadRequest request;

  request.copy_to_ram = copy_to_ram;
  request.output_address = output_address;
  request.dvd_offset = dvd_offset;
  request.length = length;
  request.partition = partition;
  request.reply_type = reply_type;

  u64 id = s_next_id++;
  request.id = id;

  request.time_started_ticks = CoreTiming::GetTicks();
  request.realtime_started_us = Common::Timer::GetTimeUs();

  s_request_queue.Push(std::move(request));
  s_request_queue_expanded.Set();

  CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read, id);
}
Beispiel #6
0
TEST(BusyLoopTest, MultiThreaded)
{
  Common::BlockingLoop loop;
  Common::Event e;
  for (int i = 0; i < 100; i++)
  {
    loop.Prepare();
    std::thread loop_thread([&]() { loop.Run([&]() { e.Set(); }); });

    // Ping - Pong
    for (int j = 0; j < 10; j++)
    {
      loop.Wakeup();
      e.Wait();

      // Just waste some time. So the main loop did fall back to the sleep state much more likely.
      Common::SleepCurrentThread(1);
    }

    for (int j = 0; j < 100; j++)
    {
      // We normally have to call Wakeup to assure the Event is triggered.
      // But this check is for an internal feature of the BlockingLoop.
      // It's implemented to fall back to a busy loop regulary.
      // If we're in the busy loop, the payload (and so the Event) is called all the time.
      // loop.Wakeup();
      e.Wait();
    }

    loop.Stop();
    loop_thread.join();
  }
}
Beispiel #7
0
// Regular thread
void DSPLLE::DSPThread(DSPLLE* dsp_lle)
{
	Common::SetCurrentThreadName("DSP thread");

	while (dsp_lle->m_bIsRunning.IsSet())
	{
		const int cycles = static_cast<int>(dsp_lle->m_cycle_count.load());
		if (cycles > 0)
		{
			std::lock_guard<std::mutex> dsp_thread_lock(dsp_lle->m_csDSPThreadActive);
			if (g_dsp_jit)
			{
				DSPCore_RunCycles(cycles);
			}
			else
			{
				DSPInterpreter::RunCyclesThread(cycles);
			}
			dsp_lle->m_cycle_count.store(0);
		}
		else
		{
			ppcEvent.Set();
			dspEvent.Wait();
		}
	}
}
Beispiel #8
0
// Regular thread
void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
{
	Common::SetCurrentThreadName("DSP thread");

	while (dsp_lle->m_bIsRunning)
	{
		int cycles = (int)dsp_lle->m_cycle_count;
		if (cycles > 0)
		{
			std::lock_guard<std::mutex> lk(dsp_lle->m_csDSPThreadActive);
			if (dspjit)
			{
				DSPCore_RunCycles(cycles);
			}
			else
			{
				DSPInterpreter::RunCyclesThread(cycles);
			}
			Common::AtomicStore(dsp_lle->m_cycle_count, 0);
		}
		else
		{
			ppcEvent.Set();
			dspEvent.Wait();
		}
	}
}
Beispiel #9
0
void Host_Message(int Id)
{
  if (Id == WM_USER_STOP)
  {
    s_running.Clear();
    updateMainFrameEvent.Set();
  }
}
Beispiel #10
0
void DSPCore_SetState(DSPCoreState new_state)
{
	core_state = new_state;
	// kick the event, in case we are waiting
	if (new_state == DSPCORE_RUNNING)
		step_event.Set();
	// Sleep(10);
	DSPHost::UpdateDebugger();
}
Beispiel #11
0
static void VideoFifo_CheckPerfQueryRequest()
{
	if (s_perfQueryRequested.IsSet())
	{
		g_perf_query->FlushResults();
		s_perfQueryRequested.Clear();
		s_perfQueryReadyEvent.Set();
	}
}
Beispiel #12
0
void VideoFifo_CheckEFBAccess()
{
	if (s_efbAccessRequested.IsSet())
	{
		s_AccessEFBResult = g_renderer->AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data);
		s_efbAccessRequested.Clear();
		s_efbAccessReadyEvent.Set();
	}
}
Beispiel #13
0
void DSPCore_SetState(State new_state)
{
  core_state = new_state;

  // kick the event, in case we are waiting
  if (new_state == State::Running)
    step_event.Set();

  Host::UpdateDebugger();
}
Beispiel #14
0
static void StopDVDThread()
{
  ASSERT(s_dvd_thread.joinable());

  // By setting s_DVD_thread_exiting, we ask the DVD thread to cleanly exit.
  // In case the request queue is empty, we need to set s_request_queue_expanded
  // so that the DVD thread will wake up and check s_DVD_thread_exiting.
  s_dvd_thread_exiting.Set();
  s_request_queue_expanded.Set();

  s_dvd_thread.join();
}
Beispiel #15
0
void DSPLLE::DSP_Update(int cycles)
{
	int dsp_cycles = cycles / 6;

	if (dsp_cycles <= 0)
		return;
// Sound stream update job has been handled by AudioDMA routine, which is more efficient
/*
	// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
	int cycles_between_ss_update;

	if (g_dspInitialize.bWii)
		cycles_between_ss_update = 121500000 / 200;
	else
		cycles_between_ss_update = 81000000 / 200;

	m_cycle_count += cycles;
	if (m_cycle_count > cycles_between_ss_update)
	{
		while (m_cycle_count > cycles_between_ss_update)
			m_cycle_count -= cycles_between_ss_update;
		soundStream->Update();
	}
*/
	if (m_bDSPThread)
	{
		if (requestDisableThread || NetPlay::IsNetPlayRunning() || Movie::IsMovieActive() || Core::g_want_determinism)
		{
			DSP_StopSoundStream();
			m_bDSPThread = false;
			requestDisableThread = false;
			SConfig::GetInstance().bDSPThread = false;
		}
	}

	// If we're not on a thread, run cycles here.
	if (!m_bDSPThread)
	{
		// ~1/6th as many cycles as the period PPC-side.
		DSPCore_RunCycles(dsp_cycles);
	}
	else
	{
		// Wait for DSP thread to complete its cycle. Note: this logic should be thought through.
		ppcEvent.Wait();
		m_cycle_count.fetch_add(dsp_cycles);
		dspEvent.Set();
	}
}
Beispiel #16
0
void DSPLLE::DSP_Update(int cycles)
{
	int dsp_cycles = cycles / 6;

	if (dsp_cycles <= 0)
		return;
// Sound stream update job has been handled by AudioDMA routine, which is more efficient
/*
	// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
	int cycles_between_ss_update;

	if (g_dspInitialize.bWii)
		cycles_between_ss_update = 121500000 / 200;
	else
		cycles_between_ss_update = 81000000 / 200;

	m_cycle_count += cycles;
	if (m_cycle_count > cycles_between_ss_update)
	{
		while (m_cycle_count > cycles_between_ss_update)
			m_cycle_count -= cycles_between_ss_update;
		soundStream->Update();
	}
*/
	// If we're not on a thread, run cycles here.
	if (!m_bDSPThread)
	{
		// ~1/6th as many cycles as the period PPC-side.
		DSPCore_RunCycles(dsp_cycles);
	}
	else
	{
		// Wait for dsp thread to complete its cycle. Note: this logic should be thought through.
		ppcEvent.Wait();
		Common::AtomicStore(m_cycle_count, dsp_cycles);
		dspEvent.Set();

	}
}
Beispiel #17
0
static void CompressAndDumpState(CompressAndDumpState_args save_args)
{
  std::lock_guard<std::mutex> lk(*save_args.buffer_mutex);

  // ScopeGuard is used here to ensure that g_compressAndDumpStateSyncEvent.Set()
  // will be called and that it will happen after the IOFile is closed.
  // Both ScopeGuard's and IOFile's finalization occur at respective object destruction time.
  // As Local (stack) objects are destructed in the reverse order of construction and "ScopeGuard
  // on_exit"
  // is created before the "IOFile f", it is guaranteed that the file will be finalized before
  // the ScopeGuard's finalization (i.e. "g_compressAndDumpStateSyncEvent.Set()" call).
  Common::ScopeGuard on_exit([]() { g_compressAndDumpStateSyncEvent.Set(); });
  // If it is not required to wait, we call finalizer early (and it won't be called again at
  // destruction).
  if (!save_args.wait)
    on_exit.Exit();

  const u8* const buffer_data = &(*(save_args.buffer_vector))[0];
  const size_t buffer_size = (save_args.buffer_vector)->size();
  std::string& filename = save_args.filename;

  // For easy debugging
  Common::SetCurrentThreadName("SaveState thread");

  // Moving to last overwritten save-state
  if (File::Exists(filename))
  {
    if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
      File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"));
    if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"))
      File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"));

    if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
      Core::DisplayMessage("Failed to move previous state to state undo backup", 1000);
    else
      File::Rename(filename + ".dtm", File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm");
  }

  if ((Movie::IsMovieActive()) && !Movie::IsJustStartingRecordingInputFromSaveState())
    Movie::SaveRecording(filename + ".dtm");
  else if (!Movie::IsMovieActive())
    File::Delete(filename + ".dtm");

  File::IOFile f(filename, "wb");
  if (!f)
  {
    Core::DisplayMessage("Could not save state", 2000);
    return;
  }

  // Setting up the header
  StateHeader header;
  strncpy(header.gameID, SConfig::GetInstance().GetUniqueID().c_str(), 6);
  header.size = g_use_compression ? (u32)buffer_size : 0;
  header.time = Common::Timer::GetDoubleTime();

  f.WriteArray(&header, 1);

  if (header.size != 0)  // non-zero header size means the state is compressed
  {
    lzo_uint i = 0;
    while (true)
    {
      lzo_uint32 cur_len = 0;
      lzo_uint out_len = 0;

      if ((i + IN_LEN) >= buffer_size)
      {
        cur_len = (lzo_uint32)(buffer_size - i);
      }
      else
      {
        cur_len = IN_LEN;
      }

      if (lzo1x_1_compress(buffer_data + i, cur_len, out, &out_len, wrkmem) != LZO_E_OK)
        PanicAlertT("Internal LZO Error - compression failed");

      // The size of the data to write is 'out_len'
      f.WriteArray((lzo_uint32*)&out_len, 1);
      f.WriteBytes(out, out_len);

      if (cur_len != IN_LEN)
        break;

      i += cur_len;
    }
  }
  else  // uncompressed
  {
    f.WriteBytes(buffer_data, buffer_size);
  }

  Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()), 2000);
  Host_UpdateMainFrame();
}
Beispiel #18
0
void CompressAndDumpState(CompressAndDumpState_args save_args)
{
	std::lock_guard<std::mutex> lk(*save_args.buffer_mutex);
	g_compressAndDumpStateSyncEvent.Set();

	const u8* const buffer_data = &(*(save_args.buffer_vector))[0];
	const size_t buffer_size = (save_args.buffer_vector)->size();
	std::string& filename = save_args.filename;

	// For easy debugging
	Common::SetCurrentThreadName("SaveState thread");

	// Moving to last overwritten save-state
	if (File::Exists(filename))
	{
		if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
			File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"));

		if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav"))
			Core::DisplayMessage("Failed to move previous state to state undo backup", 1000);
	}

	File::IOFile f(filename, "wb");
	if (!f)
	{
		Core::DisplayMessage("Could not save state", 2000);
		return;
	}

	// Setting up the header
	StateHeader header;
	memcpy(header.gameID, SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), 6);
	header.size = g_use_compression ? buffer_size : 0;

	f.WriteArray(&header, 1);

	if (0 != header.size)	// non-zero header size means the state is compressed
	{
		lzo_uint i = 0;
		while (true)
		{
			lzo_uint cur_len = 0;
			lzo_uint out_len = 0;

			if ((i + IN_LEN) >= buffer_size)
				cur_len = buffer_size - i;
			else
				cur_len = IN_LEN;

			if (lzo1x_1_compress(buffer_data + i, cur_len, out, &out_len, wrkmem) != LZO_E_OK)
				PanicAlertT("Internal LZO Error - compression failed");

			// The size of the data to write is 'out_len'
			f.WriteArray(&out_len, 1);
			f.WriteBytes(out, out_len);

			if (cur_len != IN_LEN)
				break;

			i += cur_len;
		}
	}
	else	// uncompressed
	{
		f.WriteBytes(buffer_data, buffer_size);
	}

	Core::DisplayMessage(StringFromFormat("Saved State to %s",
		filename.c_str()).c_str(), 2000);
}
Beispiel #19
0
// Description: Main FIFO update loop
// Purpose: Keep the Core HW updated about the CPU-GPU distance
void RunGpuLoop()
{

	AsyncRequests::GetInstance()->SetEnable(true);
	AsyncRequests::GetInstance()->SetPassthrough(false);

	s_gpu_mainloop.Run(
	[] {
		const SConfig& param = SConfig::GetInstance();

		g_video_backend->PeekMessages();

		// Do nothing while paused
		if (!s_emu_running_state.load())
			return;

		if (g_use_deterministic_gpu_thread)
		{
			AsyncRequests::GetInstance()->PullEvents();

			// All the fifo/CP stuff is on the CPU.  We just need to run the opcode decoder.
			u8* seen_ptr = s_video_buffer_seen_ptr;
			u8* write_ptr = s_video_buffer_write_ptr;
			// See comment in SyncGPU
			if (write_ptr > seen_ptr)
			{
				s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), nullptr, false);
				s_video_buffer_seen_ptr = write_ptr;
			}
		}
		else
		{
			SCPFifoStruct &fifo = CommandProcessor::fifo;

			AsyncRequests::GetInstance()->PullEvents();

			CommandProcessor::SetCPStatusFromGPU();

			// check if we are able to run this buffer
			while (!CommandProcessor::IsInterruptWaiting() && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint())
			{
				if (param.bSyncGPU && s_sync_ticks.load() < param.iSyncGpuMinDistance)
					break;

				u32 cyclesExecuted = 0;
				u32 readPtr = fifo.CPReadPointer;
				ReadDataFromFifo(readPtr);

				if (readPtr == fifo.CPEnd)
					readPtr = fifo.CPBase;
				else
					readPtr += 32;

				_assert_msg_(COMMANDPROCESSOR, (s32)fifo.CPReadWriteDistance - 32 >= 0 ,
					"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce instability in the game. Please report it.", fifo.CPReadWriteDistance - 32);

				u8* write_ptr = s_video_buffer_write_ptr;
				s_video_buffer_read_ptr = OpcodeDecoder_Run(DataReader(s_video_buffer_read_ptr, write_ptr), &cyclesExecuted, false);

				Common::AtomicStore(fifo.CPReadPointer, readPtr);
				Common::AtomicAdd(fifo.CPReadWriteDistance, -32);
				if ((write_ptr - s_video_buffer_read_ptr) == 0)
					Common::AtomicStore(fifo.SafeCPReadPointer, fifo.CPReadPointer);

				CommandProcessor::SetCPStatusFromGPU();

				if (param.bSyncGPU)
				{
					cyclesExecuted = (int)(cyclesExecuted / param.fSyncGpuOverclock);
					int old = s_sync_ticks.fetch_sub(cyclesExecuted);
					if (old > 0 && old - (int)cyclesExecuted <= 0)
						s_sync_wakeup_event.Set();
				}

				// This call is pretty important in DualCore mode and must be called in the FIFO Loop.
				// If we don't, s_swapRequested or s_efbAccessRequested won't be set to false
				// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
				AsyncRequests::GetInstance()->PullEvents();
			}

			// fast skip remaining GPU time if fifo is empty
			if (s_sync_ticks.load() > 0)
			{
				int old = s_sync_ticks.exchange(0);
				if (old > 0)
					s_sync_wakeup_event.Set();
			}

			// The fifo is empty and it's unlikely we will get any more work in the near future.
			// Make sure VertexManager finishes drawing any primitives it has stored in it's buffer.
			VertexManager::Flush();
		}
	}, 100);

	AsyncRequests::GetInstance()->SetEnable(false);
	AsyncRequests::GetInstance()->SetPassthrough(true);
}
Beispiel #20
0
void Host_UpdateMainFrame()
{
	updateMainFrameEvent.Set();
}
Beispiel #21
0
void DSPCore_Step()
{
  if (core_state == State::Stepping)
    step_event.Set();
}
Beispiel #22
0
void DSPCore_Step()
{
	if (core_state == DSPCORE_STEPPING)
		step_event.Set();
}
Beispiel #23
0
void Host_UpdateMainFrame()
{
  s_update_main_frame_event.Set();
}