Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move ISO decompression to a separate thread #4321

Merged
merged 7 commits into from
Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion common/include/Utilities/PersistentThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class EventListener_Thread : public IEventDispatcher<int>
virtual void OnThreadCleanup() = 0;
};

/// Set the name of the current thread
void SetNameOfCurrentThread(const char* name);

// --------------------------------------------------------------------------------------
// pxThread - Helper class for the basics of starting/managing persistent threads.
// --------------------------------------------------------------------------------------
Expand Down Expand Up @@ -194,7 +197,7 @@ class pxThread
bool _basecancel();
void _selfRunningTest(const wxChar *name) const;
void _DoSetThreadName(const wxString &name);
void _DoSetThreadName(const char *name);
void _DoSetThreadName(const char *name) { SetNameOfCurrentThread(name); }
void _internal_execute();
void _try_virtual_invoke(void (pxThread::*method)());
void _ThreadCleanup();
Expand Down
2 changes: 1 addition & 1 deletion common/src/Utilities/Darwin/DarwinThreads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void Threading::pxThread::_platform_specific_OnCleanupInThread()
}

// name can be up to 16 bytes
void Threading::pxThread::_DoSetThreadName(const char *name)
void Threading::SetNameOfCurrentThread(const char *name)
{
pthread_setname_np(name);
}
Expand Down
2 changes: 1 addition & 1 deletion common/src/Utilities/Linux/LnxThreads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void Threading::pxThread::_platform_specific_OnCleanupInThread()
// Cleanup handles here, which were opened above.
}

void Threading::pxThread::_DoSetThreadName(const char *name)
void Threading::SetNameOfCurrentThread(const char *name)
{
#if defined(__linux__)
// Extract of manpage: "The name can be up to 16 bytes long, and should be
Expand Down
2 changes: 1 addition & 1 deletion common/src/Utilities/Windows/WinThreads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ void Threading::pxThread::_platform_specific_OnCleanupInThread()
CloseHandle((HANDLE)m_native_handle);
}

void Threading::pxThread::_DoSetThreadName(const char *name)
void Threading::SetNameOfCurrentThread(const char *name)
{
// This feature needs Windows headers and MSVC's SEH support:

Expand Down
183 changes: 74 additions & 109 deletions pcsx2/CDVD/ChdFileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

#include <wx/dir.h>


bool ChdFileReader::CanHandle(const wxString& fileName)
{
if (!wxFileName::FileExists(fileName) || !fileName.Lower().EndsWith(L".chd"))
Expand All @@ -30,177 +29,143 @@ bool ChdFileReader::CanHandle(const wxString& fileName)
return true;
}

bool ChdFileReader::Open(const wxString& fileName)
bool ChdFileReader::Open2(const wxString& fileName)
{
Close2();

m_filename = fileName;

chd_file* child = NULL;
chd_file* parent = NULL;
chd_header* header = new chd_header;
chd_header* parent_header = new chd_header;
chd_header header;
chd_header parent_header;

wxString chds[8];
chds[0] = fileName;
int chd_depth = 0;
chd_error error;

do
// TODO: Unicode correctness on Windows
while (CHDERR_REQUIRES_PARENT == (error = chd_open(chds[chd_depth].c_str(), CHD_OPEN_READ, NULL, &child)))
{
// Console.Error(L"chd_open checking: %s", static_cast<const char*>(chds[chd_depth]));
error = chd_open(static_cast<const char*>(chds[chd_depth]), CHD_OPEN_READ, NULL, &child);
if (error == CHDERR_REQUIRES_PARENT)
if (chd_depth >= static_cast<int>(ArraySize(chds) - 1))
{
if (chd_read_header(static_cast<const char*>(chds[chd_depth]), header) != CHDERR_NONE)
{
Console.Error(L"chd_open chd_read_header error: %s: %s", chd_error_string(error), static_cast<const char*>(chds[chd_depth]));
delete header;
delete parent_header;
return false;
}
bool found_parent = false;
wxFileName wxfilename(chds[chd_depth]);
wxString dir_path = wxfilename.GetPath();
wxDir dir(dir_path);
if (dir.IsOpened())
Console.Error(L"CDVD: chd_open hit recursion limit searching for parents");
return false;
}
if (chd_read_header(chds[chd_depth].c_str(), &header) != CHDERR_NONE)
{
Console.Error(L"CDVD: chd_open chd_read_header error: %s: %s", chd_error_string(error), WX_STR(chds[chd_depth]));
return false;
}
bool found_parent = false;
wxFileName wxfilename(chds[chd_depth]);
wxString dir_path = wxfilename.GetPath();
wxDir dir(dir_path);
if (dir.IsOpened())
{
wxString parent_fileName;
bool cont = dir.GetFirst(&parent_fileName, wxString("*.", wxfilename.GetExt()), wxDIR_FILES | wxDIR_HIDDEN);
for (; cont; cont = dir.GetNext(&parent_fileName))
{
wxString parent_fileName;
bool cont = dir.GetFirst(&parent_fileName, wxString("*.", wxfilename.GetExt()), wxDIR_FILES | wxDIR_HIDDEN);
while (cont)
parent_fileName = wxFileName(dir_path, parent_fileName).GetFullPath();
if (chd_read_header(parent_fileName.c_str(), &parent_header) == CHDERR_NONE &&
memcmp(parent_header.sha1, header.parentsha1, sizeof(parent_header.sha1)) == 0)
{
parent_fileName = wxFileName(dir_path, parent_fileName).GetFullPath();
if (chd_read_header(static_cast<const char*>(parent_fileName), parent_header) == CHDERR_NONE &&
memcmp(parent_header->sha1, header->parentsha1, sizeof(parent_header->sha1)) == 0)
{
found_parent = true;
chds[++chd_depth] = wxString(parent_fileName);
break;
}
cont = dir.GetNext(&parent_fileName);
found_parent = true;
chds[++chd_depth] = wxString(parent_fileName);
break;
}
}
if (!found_parent)
{
Console.Error(L"chd_open no parent for: %s", static_cast<const char*>(chds[chd_depth]));
break;
}
}
} while (error == CHDERR_REQUIRES_PARENT);
delete parent_header;
if (!found_parent)
{
Console.Error(L"CDVD: chd_open no parent for: %s", WX_STR(chds[chd_depth]));
break;
}
}

if (error != CHDERR_NONE)
{
Console.Error(L"chd_open return error: %s", chd_error_string(error));
delete header;
Console.Error(L"CDVD: chd_open return error: %s", chd_error_string(error));
return false;
}

// Console.Error(L"chd_opened parent: %d %s", chd_depth, static_cast<const char*>(chds[chd_depth]));
for (int d = chd_depth - 1; d >= 0; d--)
{
// parent = child;
// child = (chd_file**)malloc(sizeof(chd_file*));
parent = child;
child = NULL;
// Console.Error(L"chd_open opening chd: %d %s", d, static_cast<const char*>(chds[d]));
error = chd_open(static_cast<const char*>(chds[d]), CHD_OPEN_READ, parent, &child);
error = chd_open(chds[d].c_str(), CHD_OPEN_READ, parent, &child);
if (error != CHDERR_NONE)
{
Console.Error(L"chd_open return error: %s", chd_error_string(error));
delete header;
Console.Error(L"CDVD: chd_open return error: %s", chd_error_string(error));
if (parent)
chd_close(parent);
return false;
}
}
ChdFile = child;
if (chd_read_header(static_cast<const char*>(chds[0]), header) != CHDERR_NONE)
if (chd_read_header(chds[0].c_str(), &header) != CHDERR_NONE)
{
Console.Error(L"chd_open chd_read_header error: %s: %s", chd_error_string(error), static_cast<const char*>(chds[0]));
delete header;
Console.Error(L"CDVD: chd_open chd_read_header error: %s: %s", chd_error_string(error), WX_STR(chds[0]));
return false;
}

// const chd_header *header = chd_get_header(ChdFile);
sector_size = header->unitbytes;
sector_count = header->unitcount;
sectors_per_hunk = header->hunkbytes / sector_size;
hunk_buffer = new u8[header->hunkbytes];
current_hunk = -1;
file_size = static_cast<u64>(header.unitbytes) * header.unitcount;
hunk_size = header.hunkbytes;
// CHD likes to use full 2448 byte blocks, but keeps the +24 offset of source ISOs
// The rest of PCSX2 likes to use 2448 byte buffers, which can't fit that so trim blocks instead
m_internalBlockSize = header.unitbytes;

delete header;
return true;
}

int ChdFileReader::ReadSync(void* pBuffer, uint sector, uint count)
ThreadedFileReader::Chunk ChdFileReader::ChunkForOffset(u64 offset)
{
u8* dst = (u8*)pBuffer;
u32 hunk = sector / sectors_per_hunk;
u32 sector_in_hunk = sector % sectors_per_hunk;
chd_error error;

for (uint i = 0; i < count; i++)
Chunk chunk = {0};
if (offset >= file_size)
{
if (current_hunk != hunk)
{
error = chd_read(ChdFile, hunk, hunk_buffer);
if (error != CHDERR_NONE)
{
Console.Error(L"chd_read return error: %s", chd_error_string(error));
// return i * m_blocksize;
}
current_hunk = hunk;
}
memcpy(dst + i * m_blocksize, hunk_buffer + sector_in_hunk * sector_size, m_blocksize);
sector_in_hunk++;
if (sector_in_hunk >= sectors_per_hunk)
{
hunk++;
sector_in_hunk = 0;
}
chunk.chunkID = -1;
}
else
{
chunk.chunkID = offset / hunk_size;
chunk.length = hunk_size;
chunk.offset = chunk.chunkID * hunk_size;
}
return m_blocksize * count;
return chunk;
}

void ChdFileReader::BeginRead(void* pBuffer, uint sector, uint count)
int ChdFileReader::ReadChunk(void *dst, s64 chunkID)
{
// TODO: Check if libchdr can read asynchronously
async_read = ReadSync(pBuffer, sector, count);
}
if (chunkID < 0)
return -1;

int ChdFileReader::FinishRead()
{
return async_read;
chd_error error = chd_read(ChdFile, chunkID, dst);
if (error != CHDERR_NONE)
{
Console.Error(L"CDVD: chd_read returned error: %s", chd_error_string(error));
return 0;
}

return hunk_size;
}

void ChdFileReader::Close()
void ChdFileReader::Close2()
{
if (hunk_buffer != NULL)
{
//free(hunk_buffer);
delete[] hunk_buffer;
hunk_buffer = NULL;
}
if (ChdFile != NULL)
{
chd_close(ChdFile);
ChdFile = NULL;
}
}

uint ChdFileReader::GetBlockSize() const
{
return m_blocksize;
}

void ChdFileReader::SetBlockSize(uint blocksize)
{
m_blocksize = blocksize;
}

u32 ChdFileReader::GetBlockCount() const
{
return sector_count;
return (file_size - m_dataoffset) / m_internalBlockSize;
}
ChdFileReader::ChdFileReader(void)
{
m_blocksize = 2048;
ChdFile = NULL;
hunk_buffer = NULL;
};
25 changes: 8 additions & 17 deletions pcsx2/CDVD/ChdFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,28 @@
*/

#pragma once
#include "AsyncFileReader.h"
#include "ThreadedFileReader.h"
#include "libchdr/chd.h"

class ChdFileReader : public AsyncFileReader
class ChdFileReader : public ThreadedFileReader
{
DeclareNoncopyableObject(ChdFileReader);

public:
virtual ~ChdFileReader(void) { Close(); };

static bool CanHandle(const wxString& fileName);
bool Open(const wxString& fileName) override;
bool Open2(const wxString& fileName) override;

int ReadSync(void* pBuffer, uint sector, uint count) override;
Chunk ChunkForOffset(u64 offset) override;
int ReadChunk(void *dst, s64 blockID) override;

void BeginRead(void* pBuffer, uint sector, uint count) override;
int FinishRead(void) override;
void CancelRead(void) override{};

void Close(void) override;
void SetBlockSize(uint blocksize);
uint GetBlockSize() const;
void Close2(void) override;
uint GetBlockCount(void) const override;
ChdFileReader(void);

private:
chd_file* ChdFile;
u8* hunk_buffer;
u32 sector_size;
u32 sector_count;
u32 sectors_per_hunk;
u32 current_hunk;
u32 async_read;
u64 file_size;
u32 hunk_size;
};
Loading