Read disc data asynchronously in DVDThread
This gives the CPU thread more time to do CPU things.
This commit is contained in:
parent
c119ad46d0
commit
54ff4bd0cb
|
@ -314,6 +314,9 @@ static void FinishExecuteCommand(u64 userdata, int cyclesLate)
|
|||
|
||||
static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples)
|
||||
{
|
||||
// TODO: Read audio data using the DVD thread instead of blocking on it?
|
||||
DVDThread::WaitUntilIdle();
|
||||
|
||||
u32 samples_processed = 0;
|
||||
do
|
||||
{
|
||||
|
@ -425,12 +428,14 @@ const DiscIO::IVolume& GetVolume()
|
|||
|
||||
bool SetVolumeName(const std::string& disc_path)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume = std::unique_ptr<DiscIO::IVolume>(DiscIO::CreateVolumeFromFilename(disc_path));
|
||||
return VolumeIsValid();
|
||||
}
|
||||
|
||||
bool SetVolumeDirectory(const std::string& full_path, bool is_wii, const std::string& apploader_path, const std::string& DOL_path)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume = std::unique_ptr<DiscIO::IVolume>(DiscIO::CreateVolumeFromDirectory(full_path, is_wii, apploader_path, DOL_path));
|
||||
return VolumeIsValid();
|
||||
}
|
||||
|
@ -459,9 +464,9 @@ bool IsDiscInside()
|
|||
// that the userdata string exists when called
|
||||
void EjectDiscCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// Empty the drive
|
||||
SetDiscInside(false);
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume.reset();
|
||||
SetDiscInside(false);
|
||||
}
|
||||
|
||||
void InsertDiscCallback(u64 userdata, int cyclesLate)
|
||||
|
@ -516,6 +521,7 @@ bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool decrypt)
|
|||
|
||||
bool ChangePartition(u64 offset)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
return s_inserted_volume->ChangePartition(offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,23 +3,42 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Flag.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/DVDInterface.h"
|
||||
#include "Core/HW/DVDThread.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace DVDThread
|
||||
{
|
||||
|
||||
static void DVDThread();
|
||||
|
||||
static void FinishRead(u64 userdata, int cyclesLate);
|
||||
static int s_finish_read;
|
||||
|
||||
static std::thread s_dvd_thread;
|
||||
static Common::Event s_dvd_thread_start_working;
|
||||
static Common::Event s_dvd_thread_done_working;
|
||||
static Common::Flag s_dvd_thread_exiting(false);
|
||||
|
||||
static std::vector<u8> s_dvd_buffer;
|
||||
static bool s_dvd_success;
|
||||
|
||||
static u64 s_dvd_offset;
|
||||
static u32 s_output_address;
|
||||
static u32 s_length;
|
||||
|
@ -32,15 +51,32 @@ static int s_callback_event_type;
|
|||
void Start()
|
||||
{
|
||||
s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
|
||||
_assert_(!s_dvd_thread.joinable());
|
||||
s_dvd_thread = std::thread(DVDThread);
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
_assert_(s_dvd_thread.joinable());
|
||||
|
||||
// The DVD thread will return if s_DVD_thread_exiting
|
||||
// is set when it starts working
|
||||
s_dvd_thread_exiting.Set();
|
||||
s_dvd_thread_start_working.Set();
|
||||
|
||||
s_dvd_thread.join();
|
||||
|
||||
s_dvd_thread_exiting.Clear();
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
|
||||
// TODO: Savestates can be smaller if s_DVD_buffer is not saved
|
||||
p.Do(s_dvd_buffer);
|
||||
p.Do(s_dvd_success);
|
||||
|
||||
p.Do(s_dvd_offset);
|
||||
p.Do(s_output_address);
|
||||
p.Do(s_length);
|
||||
|
@ -48,28 +84,71 @@ void DoState(PointerWrap &p)
|
|||
p.Do(s_callback_event_type);
|
||||
}
|
||||
|
||||
void WaitUntilIdle()
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
// Wait until DVD thread isn't working
|
||||
s_dvd_thread_done_working.Wait();
|
||||
|
||||
// Set the event again so that we still know that the DVD thread isn't working
|
||||
s_dvd_thread_done_working.Set();
|
||||
}
|
||||
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
|
||||
int callback_event_type, int ticks_until_completion)
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
s_dvd_thread_done_working.Wait();
|
||||
|
||||
s_dvd_offset = dvd_offset;
|
||||
s_output_address = output_address;
|
||||
s_length = length;
|
||||
s_decrypt = decrypt;
|
||||
s_callback_event_type = callback_event_type;
|
||||
|
||||
s_dvd_thread_start_working.Set();
|
||||
|
||||
CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read);
|
||||
}
|
||||
|
||||
static void FinishRead(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// Here is the actual disc reading
|
||||
if (!DVDInterface::DVDRead(s_dvd_offset, s_output_address, s_length, s_decrypt))
|
||||
{
|
||||
WaitUntilIdle();
|
||||
|
||||
if (s_dvd_success)
|
||||
Memory::CopyToEmu(s_output_address, s_dvd_buffer.data(), s_length);
|
||||
else
|
||||
PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").",
|
||||
s_dvd_offset, s_dvd_offset + s_length);
|
||||
}
|
||||
|
||||
// This will make the buffer take less space in savestates.
|
||||
// Reducing the size doesn't change the amount of reserved memory,
|
||||
// so this doesn't lead to extra memory allocations.
|
||||
s_dvd_buffer.resize(0);
|
||||
|
||||
// Notify the emulated software that the command has been executed
|
||||
CoreTiming::ScheduleEvent_Immediate(s_callback_event_type, DVDInterface::INT_TCINT);
|
||||
}
|
||||
|
||||
static void DVDThread()
|
||||
{
|
||||
Common::SetCurrentThreadName("DVD thread");
|
||||
|
||||
while (true)
|
||||
{
|
||||
s_dvd_thread_done_working.Set();
|
||||
|
||||
s_dvd_thread_start_working.Wait();
|
||||
|
||||
if (s_dvd_thread_exiting.IsSet())
|
||||
return;
|
||||
|
||||
s_dvd_buffer.resize(s_length);
|
||||
|
||||
s_dvd_success = DVDInterface::GetVolume().Read(s_dvd_offset, s_length, s_dvd_buffer.data(), s_decrypt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ void Start();
|
|||
void Stop();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void WaitUntilIdle();
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
|
||||
int callback_event_type, int ticks_until_completion);
|
||||
|
||||
|
|
Loading…
Reference in New Issue