Merge branch 'master' into wii-network

Conflicts:
	Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp
This commit is contained in:
Matthew Parlane 2013-02-23 17:02:58 +13:00
commit c30b8c9eae
136 changed files with 1076 additions and 1371 deletions

View file

@ -200,6 +200,7 @@ void OpenALStream::SoundLoop()
u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond();
unsigned int numSamples = (unsigned int)num_samples_to_render;
unsigned int minSamples = surround_capable ? 240 : 0; // DPL2 accepts 240 samples minimum (FWRDURATION)
numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
numSamples = m_mixer->Mix(realtimeBuffer, numSamples);
@ -236,9 +237,15 @@ void OpenALStream::SoundLoop()
// Adjust SETTING_SEQUENCE_MS to balance between lag vs hollow audio
soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)(1 / (rate * rate)));
soundTouch.setTempo(rate);
if (rate > 10)
{
soundTouch.clear();
}
}
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS);
if (nSamples > 0)
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * OAL_MAX_BUFFERS);
if (nSamples > minSamples)
{
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
if (iBuffersFilled == 0)

View file

@ -205,14 +205,7 @@ void CPUInfo::Detect()
// Turn the cpu info into a string we can show
std::string CPUInfo::Summarize()
{
std::string sum;
if (num_cores == 1)
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
else
{
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
if (HTT) sum += StringFromFormat(" (%i logical threads per physical core)", logical_cpu_count);
}
std::string sum(cpu_string);
if (bSSE) sum += ", SSE";
if (bSSE2) sum += ", SSE2";
if (bSSE3) sum += ", SSE3";

View file

@ -42,6 +42,7 @@
#endif
#include <fstream>
#include <algorithm>
#include <sys/stat.h>
#ifndef S_ISDIR
@ -196,8 +197,9 @@ bool CreateFullPath(const std::string &fullPath)
// we're done, yay!
if (position == fullPath.npos)
return true;
std::string subPath = fullPath.substr(0, position);
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath(fullPath.substr(0, position + 1));
if (!File::IsDirectory(subPath))
File::CreateDir(subPath);
@ -775,6 +777,24 @@ IOFile::~IOFile()
Close();
}
IOFile::IOFile(IOFile&& other)
: m_file(NULL), m_good(true)
{
Swap(other);
}
IOFile& IOFile::operator=(IOFile&& other)
{
IOFile((IOFile&&)other).Swap(*this);
return *this;
}
void IOFile::Swap(IOFile& other)
{
std::swap(m_file, other.m_file);
std::swap(m_good, other.m_good);
}
bool IOFile::Open(const std::string& filename, const char openmode[])
{
Close();

View file

@ -151,7 +151,7 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
// and make forgetting an fclose() harder
class IOFile : NonCopyable
class IOFile
{
public:
IOFile();
@ -159,6 +159,11 @@ public:
IOFile(const std::string& filename, const char openmode[]);
~IOFile();
IOFile(IOFile&& other);
IOFile& operator=(IOFile&& other);
void Swap(IOFile& other);
bool Open(const std::string& filename, const char openmode[]);
bool Close();
@ -213,6 +218,7 @@ public:
void Clear() { m_good = true; std::clearerr(m_file); }
private:
IOFile(const IOFile&) /*= delete*/;
IOFile& operator=(const IOFile&) /*= delete*/;
std::FILE* m_file;

View file

@ -98,8 +98,8 @@ bool GeckoSockServer::GetAvailableSock(sf::SocketTCP &sock_to_fill)
client_running = false;
clientThread.join();
recv_fifo = std::queue<u8>();
send_fifo = std::queue<u8>();
recv_fifo = std::deque<u8>();
send_fifo = std::deque<u8>();
}
clientThread = std::thread(std::mem_fun(&GeckoSockServer::ClientThread), this);
client_count++;
@ -120,28 +120,39 @@ void GeckoSockServer::ClientThread()
while (client_running)
{
u8 data;
std::size_t got = 0;
bool did_nothing = true;
{
std::lock_guard<std::mutex> lk(transfer_lock);
if (client.Receive((char*)&data, sizeof(data), got)
== sf::Socket::Disconnected)
// what's an ideal buffer size?
char data[128];
std::size_t got = 0;
if (client.Receive(&data[0], ARRAYSIZE(data), got) == sf::Socket::Disconnected)
client_running = false;
if (got)
recv_fifo.push(data);
if (send_fifo.size())
if (got != 0)
{
if (client.Send((char*)&send_fifo.front(), sizeof(u8))
== sf::Socket::Disconnected)
did_nothing = false;
recv_fifo.insert(recv_fifo.end(), &data[0], &data[got]);
}
if (!send_fifo.empty())
{
did_nothing = false;
std::vector<char> packet(send_fifo.begin(), send_fifo.end());
send_fifo.clear();
if (client.Send(&packet[0], packet.size()) == sf::Socket::Disconnected)
client_running = false;
send_fifo.pop();
}
} // unlock transfer
SLEEP(1);
if (did_nothing)
Common::YieldCPU();
}
client.Close();
@ -180,7 +191,7 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
if (!recv_fifo.empty())
{
_uData = 0x08000000 | (recv_fifo.front() << 16);
recv_fifo.pop();
recv_fifo.pop_front();
}
break;
}
@ -190,7 +201,7 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
case CMD_SEND:
{
std::lock_guard<std::mutex> lk(transfer_lock);
send_fifo.push(_uData >> 20);
send_fifo.push_back(_uData >> 20);
_uData = 0x04000000;
break;
}

View file

@ -20,6 +20,8 @@
#include "SFML/Network.hpp"
#include "Thread.h"
#include <deque>
#include <queue>
class GeckoSockServer
@ -36,8 +38,8 @@ public:
std::thread clientThread;
std::mutex transfer_lock;
std::queue<u8> send_fifo;
std::queue<u8> recv_fifo;
std::deque<u8> send_fifo;
std::deque<u8> recv_fifo;
private:
static int client_count;

View file

@ -374,7 +374,7 @@ void ExecuteCommand(u32 _Address)
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID);
WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
if (DeviceID >= 0)
{
if (DeviceName.find("/dev/es") == 0)

View file

@ -477,7 +477,7 @@ int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
u32 const Size = Memory::Read_U32(BufferIn + 0x04);
// Delay depends on size of read, that makes sense, right?
// More than ~1150K "bytes / sec" hangs NSMBWii on boot.
// Less than ~800K "bytes / sec" hangs DKCR randomly.
// Less than ~800K "bytes / sec" hangs DKCR randomly (ok, probably not true)
return SystemTimers::GetTicksPerSecond() / 975000 * Size;
break;
}
@ -498,7 +498,8 @@ int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
// case DVDLowClosePartition:
default:
// ranom numbers here!
return SystemTimers::GetTicksPerSecond() / 1500;
// More than ~1/2000th of a second hangs DKCR with DSP HLE, maybe.
return SystemTimers::GetTicksPerSecond() / 15000;
break;
}
}

View file

@ -28,17 +28,16 @@
static Common::replace_v replacements;
// This is used by several of the FileIO and /dev/fs functions
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size)
// This is used by several of the FileIO and /dev/fs functions
std::string HLE_IPC_BuildFilename(std::string path_wii, int _size)
{
std::string path_full = File::GetUserPath(D_WIIROOT_IDX);
std::string path_wii(_pFilename);
if ((path_wii.length() > 0) && (path_wii[1] == '0'))
path_full += std::string("/title"); // this looks and feel like a hack...
// Replaces chars that FAT32 can't support with strings defined in /sys/replace
for (Common::replace_v::const_iterator i = replacements.begin(); i != replacements.end(); ++i)
for (auto i = replacements.begin(); i != replacements.end(); ++i)
{
for (size_t j = 0; (j = path_wii.find(i->first, j)) != path_wii.npos; ++j)
path_wii.replace(j, 1, i->second);
@ -82,9 +81,8 @@ void HLE_IPC_CreateVirtualFATFilesystem()
}
}
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName)
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware
, m_pFileHandle(NULL)
, m_Mode(0)
, m_SeekPos(0)
{
@ -108,12 +106,9 @@ bool CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress, bool _bForce)
}
bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
{
{
m_Mode = _Mode;
u32 ReturnValue = 0;
// close the file handle if we get a reopen
//m_pFileHandle.Close();
static const char* const Modes[] =
{
@ -122,20 +117,19 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
"Write only",
"Read and Write"
};
m_Filename = std::string(HLE_IPC_BuildFilename(m_Name.c_str(), 64));
m_filepath = HLE_IPC_BuildFilename(m_Name, 64);
// The file must exist before we can open it
// It should be created by ISFS_CreateFile, not here
if (File::Exists(m_Filename))
if (File::Exists(m_filepath))
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode);
ReturnValue = m_DeviceID;
}
else
{
WARN_LOG(WII_IPC_FILEIO, "FileIO: Open (%s) failed - File doesn't exist %s", Modes[_Mode], m_Filename.c_str());
WARN_LOG(WII_IPC_FILEIO, "FileIO: Open (%s) failed - File doesn't exist %s", Modes[_Mode], m_filepath.c_str());
ReturnValue = FS_FILE_NOT_EXIST;
}
@ -145,54 +139,43 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
return true;
}
bool CWII_IPC_HLE_Device_FileIO::OpenFile()
File::IOFile CWII_IPC_HLE_Device_FileIO::OpenFile()
{
const char* open_mode = "";
switch (m_Mode)
{
case ISFS_OPEN_READ:
{
m_pFileHandle.Open(m_Filename, "rb");
open_mode = "rb";
break;
}
case ISFS_OPEN_WRITE:
{
m_pFileHandle.Open(m_Filename, "r+b");
break;
}
case ISFS_OPEN_RW:
{
m_pFileHandle.Open(m_Filename, "r+b");
open_mode = "r+b";
break;
}
default:
{
PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
break;
}
}
return m_pFileHandle.IsOpen();
return File::IOFile(m_filepath, open_mode);
}
void CWII_IPC_HLE_Device_FileIO::CloseFile()
{
m_pFileHandle.Close();
}
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
{
u32 ReturnValue = FS_RESULT_FATAL;
const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
if (OpenFile())
if (auto file = OpenFile())
{
ReturnValue = FS_RESULT_FATAL;
const s64 fileSize = m_pFileHandle.GetSize();
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx) (%08X)", SeekPosition, Mode, m_Name.c_str(), fileSize, m_DeviceID);
switch (Mode){
const u64 fileSize = file.GetSize();
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
switch (Mode)
{
case 0:
{
if ((SeekPosition >=0) && (SeekPosition <= fileSize))
@ -229,7 +212,6 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
break;
}
}
CloseFile();
}
else
{
@ -247,18 +229,18 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
if (OpenFile())
if (auto file = OpenFile())
{
if (m_Mode == ISFS_OPEN_WRITE)
if (m_Mode == ISFS_OPEN_WRITE)
{
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to read 0x%x bytes to 0x%08x on write-only file %s", Size, Address, m_Name.c_str());
}
else
else
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
m_pFileHandle.Seek(m_SeekPos, SEEK_SET);
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_pFileHandle.GetHandle());
if (ReturnValue != Size && ferror(m_pFileHandle.GetHandle()))
file.Seek(m_SeekPos, SEEK_SET);
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, file.GetHandle());
if (ReturnValue != Size && ferror(file.GetHandle()))
{
ReturnValue = FS_EACCESS;
}
@ -268,7 +250,6 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
}
}
CloseFile();
}
else
{
@ -287,23 +268,22 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
if (OpenFile())
if (auto file = OpenFile())
{
if (m_Mode == ISFS_OPEN_READ)
if (m_Mode == ISFS_OPEN_READ)
{
WARN_LOG(WII_IPC_FILEIO, "FileIO: Attempted to write 0x%x bytes from 0x%08x to read-only file %s", Size, Address, m_Name.c_str());
}
else
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
m_pFileHandle.Seek(m_SeekPos, SEEK_SET);
if (m_pFileHandle.WriteBytes(Memory::GetPointer(Address), Size))
file.Seek(m_SeekPos, SEEK_SET);
if (file.WriteBytes(Memory::GetPointer(Address), Size))
{
ReturnValue = Size;
m_SeekPos += Size;
}
}
CloseFile();
}
else
{
@ -328,17 +308,15 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
{
case ISFS_IOCTL_GETFILESTATS:
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
if (OpenFile())
if (auto file = OpenFile())
{
u32 m_FileLength = (u32)m_pFileHandle.GetSize();
u32 m_FileLength = (u32)file.GetSize();
const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
INFO_LOG(WII_IPC_FILEIO, " File: %s, Length: %i, Pos: %i", m_Name.c_str(), m_FileLength, m_SeekPos);
Memory::Write_U32(m_FileLength, BufferOut);
Memory::Write_U32(m_SeekPos, BufferOut+4);
CloseFile();
}
else
{
@ -364,30 +342,8 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
{
DoStateShared(p);
bool have_file_handle = (m_pFileHandle != 0);
s32 seek = (have_file_handle) ? (s32)m_pFileHandle.Tell() : 0;
p.Do(have_file_handle);
p.Do(m_Mode);
p.Do(seek);
p.Do(m_SeekPos);
p.Do(m_Filename);
if (p.GetMode() == PointerWrap::MODE_READ)
{
int mode = m_Mode;
bool active = m_Active;
if (have_file_handle)
{
Open(0, m_Mode);
_dbg_assert_msg_(WII_IPC_HLE, m_pFileHandle, "bad filehandle");
}
else
Close(0, true);
m_Mode = mode;
m_Active = active;
}
if (have_file_handle)
m_pFileHandle.Seek(seek, SEEK_SET);
m_filepath = HLE_IPC_BuildFilename(m_Name, 64);
}

View file

@ -21,7 +21,7 @@
#include "WII_IPC_HLE_Device.h"
#include "FileUtil.h"
std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size);
std::string HLE_IPC_BuildFilename(std::string _pFilename, int _size);
void HLE_IPC_CreateVirtualFATFilesystem();
class CWII_IPC_HLE_Device_FileIO : public IWII_IPC_HLE_Device
@ -39,8 +39,7 @@ public:
bool IOCtl(u32 _CommandAddress);
void DoState(PointerWrap &p);
bool OpenFile();
void CloseFile();
File::IOFile OpenFile();
private:
enum
@ -76,12 +75,10 @@ private:
ISFS_IOCTL_SHUTDOWN
};
File::IOFile m_pFileHandle;
u32 m_Mode;
u32 m_SeekPos;
std::string m_Filename;
std::string m_filepath;
};
#endif

View file

@ -428,7 +428,7 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B
File::CreateFullPath(FilenameRename);
// if there is already a file, delete it
if (File::Exists(FilenameRename))
if (File::Exists(Filename) && File::Exists(FilenameRename))
{
File::Delete(FilenameRename);
}

View file

@ -338,7 +338,7 @@ void Jit64::WriteRfiExitDestInEAX()
Cleanup();
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.dispatcher, true);
JMP(asm_routines.outerLoop, true);
}
void Jit64::WriteExceptionExit()

View file

@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 12;
static const u32 STATE_VERSION = 13;
struct StateHeader
{

View file

@ -215,7 +215,7 @@ bool CNANDContentLoader::Initialize(const std::string& _rName)
{
std::string TMDFileName(m_Path);
if (File::IsDirectory(TMDFileName))
if ('/' == *TMDFileName.rbegin())
TMDFileName += "title.tmd";
else
m_Path = TMDFileName.substr(0, TMDFileName.find("title.tmd"));

View file

@ -620,6 +620,7 @@ void CConfigMain::CreateGUIControls()
{
SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name = theme_selection->GetStringSelection();
main_frame->InitBitmaps();
main_frame->UpdateGameList();
}));
auto const scInterface = new wxBoxSizer(wxHORIZONTAL);

View file

@ -624,7 +624,9 @@ void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event)
int stream_size = Common::swap16(objectdata);
objectdata += 2;
wxString newLabel = wxString::Format(wxT("%08X: %02X %04X "), obj_offset, cmd, stream_size);
if ((objectdata_end - objectdata) % stream_size) newLabel += _("NOTE: Stream size doesn't match actual data length\n");
if (stream_size && ((objectdata_end - objectdata) % stream_size))
newLabel += _("NOTE: Stream size doesn't match actual data length\n");
while (objectdata < objectdata_end)
{
newLabel += wxString::Format(wxT("%02X"), *objectdata++);

View file

@ -14,8 +14,8 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _INTERFACEGLX_H_
#define _INTERFACEGLX_H_
#ifndef _INTERFACEEGL_H_
#define _INTERFACEEGL_H_
#include <EGL/egl.h>
#ifdef USE_GLES

View file

@ -34,7 +34,7 @@
#include "FileSearch.h"
#include "CompressedBlob.h"
#include "ChunkFile.h"
#include "../resources/no_banner.cpp"
#include "ConfigManager.h"
#define CACHE_REVISION 0x10F
@ -174,10 +174,16 @@ GameListItem::GameListItem(const std::string& _rFileName)
}
else
{
std::string theme = SConfig::GetInstance().m_LocalCoreStartupParameter.theme_name + "/";
std::string dir = File::GetUserPath(D_THEMES_IDX) + theme;
#if !defined(_WIN32)
// If theme does not exist in user's dir load from shared directory
if (!File::Exists(dir))
dir = SHARED_USER_DIR THEMES_DIR "/" + theme;
#endif
// default banner
wxMemoryInputStream istream(no_banner_png, sizeof no_banner_png);
wxImage iNoBanner(istream, wxBITMAP_TYPE_PNG);
m_Image = iNoBanner;
m_Image = wxImage(dir + "nobanner.png", wxBITMAP_TYPE_PNG);
}
}

View file

@ -519,7 +519,7 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
button_sizer->Add(add_button, 1, 0, 5);
}
range_slider = new wxSlider(this, -1, SLIDER_TICK_COUNT, 0, SLIDER_TICK_COUNT * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/);
range_slider = new wxSlider(this, -1, SLIDER_TICK_COUNT, -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/);
range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT));

View file

@ -1,279 +0,0 @@
static const unsigned char no_banner_png[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20,
0x08, 0x06, 0x00, 0x00, 0x00, 0xed, 0xc0, 0x7d, 0x54, 0x00, 0x00, 0x00,
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b,
0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x0a, 0x4f, 0x69, 0x43,
0x43, 0x50, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x20,
0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x00,
0x00, 0x78, 0xda, 0x9d, 0x53, 0x67, 0x54, 0x53, 0xe9, 0x16, 0x3d, 0xf7,
0xde, 0xf4, 0x42, 0x4b, 0x88, 0x80, 0x94, 0x4b, 0x6f, 0x52, 0x15, 0x08,
0x20, 0x52, 0x42, 0x8b, 0x80, 0x14, 0x91, 0x26, 0x2a, 0x21, 0x09, 0x10,
0x4a, 0x88, 0x21, 0xa1, 0xd9, 0x15, 0x51, 0xc1, 0x11, 0x45, 0x45, 0x04,
0x1b, 0xc8, 0xa0, 0x88, 0x03, 0x8e, 0x8e, 0x80, 0x8c, 0x15, 0x51, 0x2c,
0x0c, 0x8a, 0x0a, 0xd8, 0x07, 0xe4, 0x21, 0xa2, 0x8e, 0x83, 0xa3, 0x88,
0x8a, 0xca, 0xfb, 0xe1, 0x7b, 0xa3, 0x6b, 0xd6, 0xbc, 0xf7, 0xe6, 0xcd,
0xfe, 0xb5, 0xd7, 0x3e, 0xe7, 0xac, 0xf3, 0x9d, 0xb3, 0xcf, 0x07, 0xc0,
0x08, 0x0c, 0x96, 0x48, 0x33, 0x51, 0x35, 0x80, 0x0c, 0xa9, 0x42, 0x1e,
0x11, 0xe0, 0x83, 0xc7, 0xc4, 0xc6, 0xe1, 0xe4, 0x2e, 0x40, 0x81, 0x0a,
0x24, 0x70, 0x00, 0x10, 0x08, 0xb3, 0x64, 0x21, 0x73, 0xfd, 0x23, 0x01,
0x00, 0xf8, 0x7e, 0x3c, 0x3c, 0x2b, 0x22, 0xc0, 0x07, 0xbe, 0x00, 0x01,
0x78, 0xd3, 0x0b, 0x08, 0x00, 0xc0, 0x4d, 0x9b, 0xc0, 0x30, 0x1c, 0x87,
0xff, 0x0f, 0xea, 0x42, 0x99, 0x5c, 0x01, 0x80, 0x84, 0x01, 0xc0, 0x74,
0x91, 0x38, 0x4b, 0x08, 0x80, 0x14, 0x00, 0x40, 0x7a, 0x8e, 0x42, 0xa6,
0x00, 0x40, 0x46, 0x01, 0x80, 0x9d, 0x98, 0x26, 0x53, 0x00, 0xa0, 0x04,
0x00, 0x60, 0xcb, 0x63, 0x62, 0xe3, 0x00, 0x50, 0x2d, 0x00, 0x60, 0x27,
0x7f, 0xe6, 0xd3, 0x00, 0x80, 0x9d, 0xf8, 0x99, 0x7b, 0x01, 0x00, 0x5b,
0x94, 0x21, 0x15, 0x01, 0xa0, 0x91, 0x00, 0x20, 0x13, 0x65, 0x88, 0x44,
0x00, 0x68, 0x3b, 0x00, 0xac, 0xcf, 0x56, 0x8a, 0x45, 0x00, 0x58, 0x30,
0x00, 0x14, 0x66, 0x4b, 0xc4, 0x39, 0x00, 0xd8, 0x2d, 0x00, 0x30, 0x49,
0x57, 0x66, 0x48, 0x00, 0xb0, 0xb7, 0x00, 0xc0, 0xce, 0x10, 0x0b, 0xb2,
0x00, 0x08, 0x0c, 0x00, 0x30, 0x51, 0x88, 0x85, 0x29, 0x00, 0x04, 0x7b,
0x00, 0x60, 0xc8, 0x23, 0x23, 0x78, 0x00, 0x84, 0x99, 0x00, 0x14, 0x46,
0xf2, 0x57, 0x3c, 0xf1, 0x2b, 0xae, 0x10, 0xe7, 0x2a, 0x00, 0x00, 0x78,
0x99, 0xb2, 0x3c, 0xb9, 0x24, 0x39, 0x45, 0x81, 0x5b, 0x08, 0x2d, 0x71,
0x07, 0x57, 0x57, 0x2e, 0x1e, 0x28, 0xce, 0x49, 0x17, 0x2b, 0x14, 0x36,
0x61, 0x02, 0x61, 0x9a, 0x40, 0x2e, 0xc2, 0x79, 0x99, 0x19, 0x32, 0x81,
0x34, 0x0f, 0xe0, 0xf3, 0xcc, 0x00, 0x00, 0xa0, 0x91, 0x15, 0x11, 0xe0,
0x83, 0xf3, 0xfd, 0x78, 0xce, 0x0e, 0xae, 0xce, 0xce, 0x36, 0x8e, 0xb6,
0x0e, 0x5f, 0x2d, 0xea, 0xbf, 0x06, 0xff, 0x22, 0x62, 0x62, 0xe3, 0xfe,
0xe5, 0xcf, 0xab, 0x70, 0x40, 0x00, 0x00, 0xe1, 0x74, 0x7e, 0xd1, 0xfe,
0x2c, 0x2f, 0xb3, 0x1a, 0x80, 0x3b, 0x06, 0x80, 0x6d, 0xfe, 0xa2, 0x25,
0xee, 0x04, 0x68, 0x5e, 0x0b, 0xa0, 0x75, 0xf7, 0x8b, 0x66, 0xb2, 0x0f,
0x40, 0xb5, 0x00, 0xa0, 0xe9, 0xda, 0x57, 0xf3, 0x70, 0xf8, 0x7e, 0x3c,
0x3c, 0x45, 0xa1, 0x90, 0xb9, 0xd9, 0xd9, 0xe5, 0xe4, 0xe4, 0xd8, 0x4a,
0xc4, 0x42, 0x5b, 0x61, 0xca, 0x57, 0x7d, 0xfe, 0x67, 0xc2, 0x5f, 0xc0,
0x57, 0xfd, 0x6c, 0xf9, 0x7e, 0x3c, 0xfc, 0xf7, 0xf5, 0xe0, 0xbe, 0xe2,
0x24, 0x81, 0x32, 0x5d, 0x81, 0x47, 0x04, 0xf8, 0xe0, 0xc2, 0xcc, 0xf4,
0x4c, 0xa5, 0x1c, 0xcf, 0x92, 0x09, 0x84, 0x62, 0xdc, 0xe6, 0x8f, 0x47,
0xfc, 0xb7, 0x0b, 0xff, 0xfc, 0x1d, 0xd3, 0x22, 0xc4, 0x49, 0x62, 0xb9,
0x58, 0x2a, 0x14, 0xe3, 0x51, 0x12, 0x71, 0x8e, 0x44, 0x9a, 0x8c, 0xf3,
0x32, 0xa5, 0x22, 0x89, 0x42, 0x92, 0x29, 0xc5, 0x25, 0xd2, 0xff, 0x64,
0xe2, 0xdf, 0x2c, 0xfb, 0x03, 0x3e, 0xdf, 0x35, 0x00, 0xb0, 0x6a, 0x3e,
0x01, 0x7b, 0x91, 0x2d, 0xa8, 0x5d, 0x63, 0x03, 0xf6, 0x4b, 0x27, 0x10,
0x58, 0x74, 0xc0, 0xe2, 0xf7, 0x00, 0x00, 0xf2, 0xbb, 0x6f, 0xc1, 0xd4,
0x28, 0x08, 0x03, 0x80, 0x68, 0x83, 0xe1, 0xcf, 0x77, 0xff, 0xef, 0x3f,
0xfd, 0x47, 0xa0, 0x25, 0x00, 0x80, 0x66, 0x49, 0x92, 0x71, 0x00, 0x00,
0x5e, 0x44, 0x24, 0x2e, 0x54, 0xca, 0xb3, 0x3f, 0xc7, 0x08, 0x00, 0x00,
0x44, 0xa0, 0x81, 0x2a, 0xb0, 0x41, 0x1b, 0xf4, 0xc1, 0x18, 0x2c, 0xc0,
0x06, 0x1c, 0xc1, 0x05, 0xdc, 0xc1, 0x0b, 0xfc, 0x60, 0x36, 0x84, 0x42,
0x24, 0xc4, 0xc2, 0x42, 0x10, 0x42, 0x0a, 0x64, 0x80, 0x1c, 0x72, 0x60,
0x29, 0xac, 0x82, 0x42, 0x28, 0x86, 0xcd, 0xb0, 0x1d, 0x2a, 0x60, 0x2f,
0xd4, 0x40, 0x1d, 0x34, 0xc0, 0x51, 0x68, 0x86, 0x93, 0x70, 0x0e, 0x2e,
0xc2, 0x55, 0xb8, 0x0e, 0x3d, 0x70, 0x0f, 0xfa, 0x61, 0x08, 0x9e, 0xc1,
0x28, 0xbc, 0x81, 0x09, 0x04, 0x41, 0xc8, 0x08, 0x13, 0x61, 0x21, 0xda,
0x88, 0x01, 0x62, 0x8a, 0x58, 0x23, 0x8e, 0x08, 0x17, 0x99, 0x85, 0xf8,
0x21, 0xc1, 0x48, 0x04, 0x12, 0x8b, 0x24, 0x20, 0xc9, 0x88, 0x14, 0x51,
0x22, 0x4b, 0x91, 0x35, 0x48, 0x31, 0x52, 0x8a, 0x54, 0x20, 0x55, 0x48,
0x1d, 0xf2, 0x3d, 0x72, 0x02, 0x39, 0x87, 0x5c, 0x46, 0xba, 0x91, 0x3b,
0xc8, 0x00, 0x32, 0x82, 0xfc, 0x86, 0xbc, 0x47, 0x31, 0x94, 0x81, 0xb2,
0x51, 0x3d, 0xd4, 0x0c, 0xb5, 0x43, 0xb9, 0xa8, 0x37, 0x1a, 0x84, 0x46,
0xa2, 0x0b, 0xd0, 0x64, 0x74, 0x31, 0x9a, 0x8f, 0x16, 0xa0, 0x9b, 0xd0,
0x72, 0xb4, 0x1a, 0x3d, 0x8c, 0x36, 0xa1, 0xe7, 0xd0, 0xab, 0x68, 0x0f,
0xda, 0x8f, 0x3e, 0x43, 0xc7, 0x30, 0xc0, 0xe8, 0x18, 0x07, 0x33, 0xc4,
0x6c, 0x30, 0x2e, 0xc6, 0xc3, 0x42, 0xb1, 0x38, 0x2c, 0x09, 0x93, 0x63,
0xcb, 0xb1, 0x22, 0xac, 0x0c, 0xab, 0xc6, 0x1a, 0xb0, 0x56, 0xac, 0x03,
0xbb, 0x89, 0xf5, 0x63, 0xcf, 0xb1, 0x77, 0x04, 0x12, 0x81, 0x45, 0xc0,
0x09, 0x36, 0x04, 0x77, 0x42, 0x20, 0x61, 0x1e, 0x41, 0x48, 0x58, 0x4c,
0x58, 0x4e, 0xd8, 0x48, 0xa8, 0x20, 0x1c, 0x24, 0x34, 0x11, 0xda, 0x09,
0x37, 0x09, 0x03, 0x84, 0x51, 0xc2, 0x27, 0x22, 0x93, 0xa8, 0x4b, 0xb4,
0x26, 0xba, 0x11, 0xf9, 0xc4, 0x18, 0x62, 0x32, 0x31, 0x87, 0x58, 0x48,
0x2c, 0x23, 0xd6, 0x12, 0x8f, 0x13, 0x2f, 0x10, 0x7b, 0x88, 0x43, 0xc4,
0x37, 0x24, 0x12, 0x89, 0x43, 0x32, 0x27, 0xb9, 0x90, 0x02, 0x49, 0xb1,
0xa4, 0x54, 0xd2, 0x12, 0xd2, 0x46, 0xd2, 0x6e, 0x52, 0x23, 0xe9, 0x2c,
0xa9, 0x9b, 0x34, 0x48, 0x1a, 0x23, 0x93, 0xc9, 0xda, 0x64, 0x6b, 0xb2,
0x07, 0x39, 0x94, 0x2c, 0x20, 0x2b, 0xc8, 0x85, 0xe4, 0x9d, 0xe4, 0xc3,
0xe4, 0x33, 0xe4, 0x1b, 0xe4, 0x21, 0xf2, 0x5b, 0x0a, 0x9d, 0x62, 0x40,
0x71, 0xa4, 0xf8, 0x53, 0xe2, 0x28, 0x52, 0xca, 0x6a, 0x4a, 0x19, 0xe5,
0x10, 0xe5, 0x34, 0xe5, 0x06, 0x65, 0x98, 0x32, 0x41, 0x55, 0xa3, 0x9a,
0x52, 0xdd, 0xa8, 0xa1, 0x54, 0x11, 0x35, 0x8f, 0x5a, 0x42, 0xad, 0xa1,
0xb6, 0x52, 0xaf, 0x51, 0x87, 0xa8, 0x13, 0x34, 0x75, 0x9a, 0x39, 0xcd,
0x83, 0x16, 0x49, 0x4b, 0xa5, 0xad, 0xa2, 0x95, 0xd3, 0x1a, 0x68, 0x17,
0x68, 0xf7, 0x69, 0xaf, 0xe8, 0x74, 0xba, 0x11, 0xdd, 0x95, 0x1e, 0x4e,
0x97, 0xd0, 0x57, 0xd2, 0xcb, 0xe9, 0x47, 0xe8, 0x97, 0xe8, 0x03, 0xf4,
0x77, 0x0c, 0x0d, 0x86, 0x15, 0x83, 0xc7, 0x88, 0x67, 0x28, 0x19, 0x9b,
0x18, 0x07, 0x18, 0x67, 0x19, 0x77, 0x18, 0xaf, 0x98, 0x4c, 0xa6, 0x19,
0xd3, 0x8b, 0x19, 0xc7, 0x54, 0x30, 0x37, 0x31, 0xeb, 0x98, 0xe7, 0x99,
0x0f, 0x99, 0x6f, 0x55, 0x58, 0x2a, 0xb6, 0x2a, 0x7c, 0x15, 0x91, 0xca,
0x0a, 0x95, 0x4a, 0x95, 0x26, 0x95, 0x1b, 0x2a, 0x2f, 0x54, 0xa9, 0xaa,
0xa6, 0xaa, 0xde, 0xaa, 0x0b, 0x55, 0xf3, 0x55, 0xcb, 0x54, 0x8f, 0xa9,
0x5e, 0x53, 0x7d, 0xae, 0x46, 0x55, 0x33, 0x53, 0xe3, 0xa9, 0x09, 0xd4,
0x96, 0xab, 0x55, 0xaa, 0x9d, 0x50, 0xeb, 0x53, 0x1b, 0x53, 0x67, 0xa9,
0x3b, 0xa8, 0x87, 0xaa, 0x67, 0xa8, 0x6f, 0x54, 0x3f, 0xa4, 0x7e, 0x59,
0xfd, 0x89, 0x06, 0x59, 0xc3, 0x4c, 0xc3, 0x4f, 0x43, 0xa4, 0x51, 0xa0,
0xb1, 0x5f, 0xe3, 0xbc, 0xc6, 0x20, 0x0b, 0x63, 0x19, 0xb3, 0x78, 0x2c,
0x21, 0x6b, 0x0d, 0xab, 0x86, 0x75, 0x81, 0x35, 0xc4, 0x26, 0xb1, 0xcd,
0xd9, 0x7c, 0x76, 0x2a, 0xbb, 0x98, 0xfd, 0x1d, 0xbb, 0x8b, 0x3d, 0xaa,
0xa9, 0xa1, 0x39, 0x43, 0x33, 0x4a, 0x33, 0x57, 0xb3, 0x52, 0xf3, 0x94,
0x66, 0x3f, 0x07, 0xe3, 0x98, 0x71, 0xf8, 0x9c, 0x74, 0x4e, 0x09, 0xe7,
0x28, 0xa7, 0x97, 0xf3, 0x7e, 0x8a, 0xde, 0x14, 0xef, 0x29, 0xe2, 0x29,
0x1b, 0xa6, 0x34, 0x4c, 0xb9, 0x31, 0x65, 0x5c, 0x6b, 0xaa, 0x96, 0x97,
0x96, 0x58, 0xab, 0x48, 0xab, 0x51, 0xab, 0x47, 0xeb, 0xbd, 0x36, 0xae,
0xed, 0xa7, 0x9d, 0xa6, 0xbd, 0x45, 0xbb, 0x59, 0xfb, 0x81, 0x0e, 0x41,
0xc7, 0x4a, 0x27, 0x5c, 0x27, 0x47, 0x67, 0x8f, 0xce, 0x05, 0x9d, 0xe7,
0x53, 0xd9, 0x53, 0xdd, 0xa7, 0x0a, 0xa7, 0x16, 0x4d, 0x3d, 0x3a, 0xf5,
0xae, 0x2e, 0xaa, 0x6b, 0xa5, 0x1b, 0xa1, 0xbb, 0x44, 0x77, 0xbf, 0x6e,
0xa7, 0xee, 0x98, 0x9e, 0xbe, 0x5e, 0x80, 0x9e, 0x4c, 0x6f, 0xa7, 0xde,
0x79, 0xbd, 0xe7, 0xfa, 0x1c, 0x7d, 0x2f, 0xfd, 0x54, 0xfd, 0x6d, 0xfa,
0xa7, 0xf5, 0x47, 0x0c, 0x58, 0x06, 0xb3, 0x0c, 0x24, 0x06, 0xdb, 0x0c,
0xce, 0x18, 0x3c, 0xc5, 0x35, 0x71, 0x6f, 0x3c, 0x1d, 0x2f, 0xc7, 0xdb,
0xf1, 0x51, 0x43, 0x5d, 0xc3, 0x40, 0x43, 0xa5, 0x61, 0x95, 0x61, 0x97,
0xe1, 0x84, 0x91, 0xb9, 0xd1, 0x3c, 0xa3, 0xd5, 0x46, 0x8d, 0x46, 0x0f,
0x8c, 0x69, 0xc6, 0x5c, 0xe3, 0x24, 0xe3, 0x6d, 0xc6, 0x6d, 0xc6, 0xa3,
0x26, 0x06, 0x26, 0x21, 0x26, 0x4b, 0x4d, 0xea, 0x4d, 0xee, 0x9a, 0x52,
0x4d, 0xb9, 0xa6, 0x29, 0xa6, 0x3b, 0x4c, 0x3b, 0x4c, 0xc7, 0xcd, 0xcc,
0xcd, 0xa2, 0xcd, 0xd6, 0x99, 0x35, 0x9b, 0x3d, 0x31, 0xd7, 0x32, 0xe7,
0x9b, 0xe7, 0x9b, 0xd7, 0x9b, 0xdf, 0xb7, 0x60, 0x5a, 0x78, 0x5a, 0x2c,
0xb6, 0xa8, 0xb6, 0xb8, 0x65, 0x49, 0xb2, 0xe4, 0x5a, 0xa6, 0x59, 0xee,
0xb6, 0xbc, 0x6e, 0x85, 0x5a, 0x39, 0x59, 0xa5, 0x58, 0x55, 0x5a, 0x5d,
0xb3, 0x46, 0xad, 0x9d, 0xad, 0x25, 0xd6, 0xbb, 0xad, 0xbb, 0xa7, 0x11,
0xa7, 0xb9, 0x4e, 0x93, 0x4e, 0xab, 0x9e, 0xd6, 0x67, 0xc3, 0xb0, 0xf1,
0xb6, 0xc9, 0xb6, 0xa9, 0xb7, 0x19, 0xb0, 0xe5, 0xd8, 0x06, 0xdb, 0xae,
0xb6, 0x6d, 0xb6, 0x7d, 0x61, 0x67, 0x62, 0x17, 0x67, 0xb7, 0xc5, 0xae,
0xc3, 0xee, 0x93, 0xbd, 0x93, 0x7d, 0xba, 0x7d, 0x8d, 0xfd, 0x3d, 0x07,
0x0d, 0x87, 0xd9, 0x0e, 0xab, 0x1d, 0x5a, 0x1d, 0x7e, 0x73, 0xb4, 0x72,
0x14, 0x3a, 0x56, 0x3a, 0xde, 0x9a, 0xce, 0x9c, 0xee, 0x3f, 0x7d, 0xc5,
0xf4, 0x96, 0xe9, 0x2f, 0x67, 0x58, 0xcf, 0x10, 0xcf, 0xd8, 0x33, 0xe3,
0xb6, 0x13, 0xcb, 0x29, 0xc4, 0x69, 0x9d, 0x53, 0x9b, 0xd3, 0x47, 0x67,
0x17, 0x67, 0xb9, 0x73, 0x83, 0xf3, 0x88, 0x8b, 0x89, 0x4b, 0x82, 0xcb,
0x2e, 0x97, 0x3e, 0x2e, 0x9b, 0x1b, 0xc6, 0xdd, 0xc8, 0xbd, 0xe4, 0x4a,
0x74, 0xf5, 0x71, 0x5d, 0xe1, 0x7a, 0xd2, 0xf5, 0x9d, 0x9b, 0xb3, 0x9b,
0xc2, 0xed, 0xa8, 0xdb, 0xaf, 0xee, 0x36, 0xee, 0x69, 0xee, 0x87, 0xdc,
0x9f, 0xcc, 0x34, 0x9f, 0x29, 0x9e, 0x59, 0x33, 0x73, 0xd0, 0xc3, 0xc8,
0x43, 0xe0, 0x51, 0xe5, 0xd1, 0x3f, 0x0b, 0x9f, 0x95, 0x30, 0x6b, 0xdf,
0xac, 0x7e, 0x4f, 0x43, 0x4f, 0x81, 0x67, 0xb5, 0xe7, 0x23, 0x2f, 0x63,
0x2f, 0x91, 0x57, 0xad, 0xd7, 0xb0, 0xb7, 0xa5, 0x77, 0xaa, 0xf7, 0x61,
0xef, 0x17, 0x3e, 0xf6, 0x3e, 0x72, 0x9f, 0xe3, 0x3e, 0xe3, 0x3c, 0x37,
0xde, 0x32, 0xde, 0x59, 0x5f, 0xcc, 0x37, 0xc0, 0xb7, 0xc8, 0xb7, 0xcb,
0x4f, 0xc3, 0x6f, 0x9e, 0x5f, 0x85, 0xdf, 0x43, 0x7f, 0x23, 0xff, 0x64,
0xff, 0x7a, 0xff, 0xd1, 0x00, 0xa7, 0x80, 0x25, 0x01, 0x67, 0x03, 0x89,
0x81, 0x41, 0x81, 0x5b, 0x02, 0xfb, 0xf8, 0x7a, 0x7c, 0x21, 0xbf, 0x8e,
0x3f, 0x3a, 0xdb, 0x65, 0xf6, 0xb2, 0xd9, 0xed, 0x41, 0x8c, 0xa0, 0xb9,
0x41, 0x15, 0x41, 0x8f, 0x82, 0xad, 0x82, 0xe5, 0xc1, 0xad, 0x21, 0x68,
0xc8, 0xec, 0x90, 0xad, 0x21, 0xf7, 0xe7, 0x98, 0xce, 0x91, 0xce, 0x69,
0x0e, 0x85, 0x50, 0x7e, 0xe8, 0xd6, 0xd0, 0x07, 0x61, 0xe6, 0x61, 0x8b,
0xc3, 0x7e, 0x0c, 0x27, 0x85, 0x87, 0x85, 0x57, 0x86, 0x3f, 0x8e, 0x70,
0x88, 0x58, 0x1a, 0xd1, 0x31, 0x97, 0x35, 0x77, 0xd1, 0xdc, 0x43, 0x73,
0xdf, 0x44, 0xfa, 0x44, 0x96, 0x44, 0xde, 0x9b, 0x67, 0x31, 0x4f, 0x39,
0xaf, 0x2d, 0x4a, 0x35, 0x2a, 0x3e, 0xaa, 0x2e, 0x6a, 0x3c, 0xda, 0x37,
0xba, 0x34, 0xba, 0x3f, 0xc6, 0x2e, 0x66, 0x59, 0xcc, 0xd5, 0x58, 0x9d,
0x58, 0x49, 0x6c, 0x4b, 0x1c, 0x39, 0x2e, 0x2a, 0xae, 0x36, 0x6e, 0x6c,
0xbe, 0xdf, 0xfc, 0xed, 0xf3, 0x87, 0xe2, 0x9d, 0xe2, 0x0b, 0xe3, 0x7b,
0x17, 0x98, 0x2f, 0xc8, 0x5d, 0x70, 0x79, 0xa1, 0xce, 0xc2, 0xf4, 0x85,
0xa7, 0x16, 0xa9, 0x2e, 0x12, 0x2c, 0x3a, 0x96, 0x40, 0x4c, 0x88, 0x4e,
0x38, 0x94, 0xf0, 0x41, 0x10, 0x2a, 0xa8, 0x16, 0x8c, 0x25, 0xf2, 0x13,
0x77, 0x25, 0x8e, 0x0a, 0x79, 0xc2, 0x1d, 0xc2, 0x67, 0x22, 0x2f, 0xd1,
0x36, 0xd1, 0x88, 0xd8, 0x43, 0x5c, 0x2a, 0x1e, 0x4e, 0xf2, 0x48, 0x2a,
0x4d, 0x7a, 0x92, 0xec, 0x91, 0xbc, 0x35, 0x79, 0x24, 0xc5, 0x33, 0xa5,
0x2c, 0xe5, 0xb9, 0x84, 0x27, 0xa9, 0x90, 0xbc, 0x4c, 0x0d, 0x4c, 0xdd,
0x9b, 0x3a, 0x9e, 0x16, 0x9a, 0x76, 0x20, 0x6d, 0x32, 0x3d, 0x3a, 0xbd,
0x31, 0x83, 0x92, 0x91, 0x90, 0x71, 0x42, 0xaa, 0x21, 0x4d, 0x93, 0xb6,
0x67, 0xea, 0x67, 0xe6, 0x66, 0x76, 0xcb, 0xac, 0x65, 0x85, 0xb2, 0xfe,
0xc5, 0x6e, 0x8b, 0xb7, 0x2f, 0x1e, 0x95, 0x07, 0xc9, 0x6b, 0xb3, 0x90,
0xac, 0x05, 0x59, 0x2d, 0x0a, 0xb6, 0x42, 0xa6, 0xe8, 0x54, 0x5a, 0x28,
0xd7, 0x2a, 0x07, 0xb2, 0x67, 0x65, 0x57, 0x66, 0xbf, 0xcd, 0x89, 0xca,
0x39, 0x96, 0xab, 0x9e, 0x2b, 0xcd, 0xed, 0xcc, 0xb3, 0xca, 0xdb, 0x90,
0x37, 0x9c, 0xef, 0x9f, 0xff, 0xed, 0x12, 0xc2, 0x12, 0xe1, 0x92, 0xb6,
0xa5, 0x86, 0x4b, 0x57, 0x2d, 0x1d, 0x58, 0xe6, 0xbd, 0xac, 0x6a, 0x39,
0xb2, 0x3c, 0x71, 0x79, 0xdb, 0x0a, 0xe3, 0x15, 0x05, 0x2b, 0x86, 0x56,
0x06, 0xac, 0x3c, 0xb8, 0x8a, 0xb6, 0x2a, 0x6d, 0xd5, 0x4f, 0xab, 0xed,
0x57, 0x97, 0xae, 0x7e, 0xbd, 0x26, 0x7a, 0x4d, 0x6b, 0x81, 0x5e, 0xc1,
0xca, 0x82, 0xc1, 0xb5, 0x01, 0x6b, 0xeb, 0x0b, 0x55, 0x0a, 0xe5, 0x85,
0x7d, 0xeb, 0xdc, 0xd7, 0xed, 0x5d, 0x4f, 0x58, 0x2f, 0x59, 0xdf, 0xb5,
0x61, 0xfa, 0x86, 0x9d, 0x1b, 0x3e, 0x15, 0x89, 0x8a, 0xae, 0x14, 0xdb,
0x17, 0x97, 0x15, 0x7f, 0xd8, 0x28, 0xdc, 0x78, 0xe5, 0x1b, 0x87, 0x6f,
0xca, 0xbf, 0x99, 0xdc, 0x94, 0xb4, 0xa9, 0xab, 0xc4, 0xb9, 0x64, 0xcf,
0x66, 0xd2, 0x66, 0xe9, 0xe6, 0xde, 0x2d, 0x9e, 0x5b, 0x0e, 0x96, 0xaa,
0x97, 0xe6, 0x97, 0x0e, 0x6e, 0x0d, 0xd9, 0xda, 0xb4, 0x0d, 0xdf, 0x56,
0xb4, 0xed, 0xf5, 0xf6, 0x45, 0xdb, 0x2f, 0x97, 0xcd, 0x28, 0xdb, 0xbb,
0x83, 0xb6, 0x43, 0xb9, 0xa3, 0xbf, 0x3c, 0xb8, 0xbc, 0x65, 0xa7, 0xc9,
0xce, 0xcd, 0x3b, 0x3f, 0x54, 0xa4, 0x54, 0xf4, 0x54, 0xfa, 0x54, 0x36,
0xee, 0xd2, 0xdd, 0xb5, 0x61, 0xd7, 0xf8, 0x6e, 0xd1, 0xee, 0x1b, 0x7b,
0xbc, 0xf6, 0x34, 0xec, 0xd5, 0xdb, 0x5b, 0xbc, 0xf7, 0xfd, 0x3e, 0xc9,
0xbe, 0xdb, 0x55, 0x01, 0x55, 0x4d, 0xd5, 0x66, 0xd5, 0x65, 0xfb, 0x49,
0xfb, 0xb3, 0xf7, 0x3f, 0xae, 0x89, 0xaa, 0xe9, 0xf8, 0x96, 0xfb, 0x6d,
0x5d, 0xad, 0x4e, 0x6d, 0x71, 0xed, 0xc7, 0x03, 0xd2, 0x03, 0xfd, 0x07,
0x23, 0x0e, 0xb6, 0xd7, 0xb9, 0xd4, 0xd5, 0x1d, 0xd2, 0x3d, 0x54, 0x52,
0x8f, 0xd6, 0x2b, 0xeb, 0x47, 0x0e, 0xc7, 0x1f, 0xbe, 0xfe, 0x9d, 0xef,
0x77, 0x2d, 0x0d, 0x36, 0x0d, 0x55, 0x8d, 0x9c, 0xc6, 0xe2, 0x23, 0x70,
0x44, 0x79, 0xe4, 0xe9, 0xf7, 0x09, 0xdf, 0xf7, 0x1e, 0x0d, 0x3a, 0xda,
0x76, 0x8c, 0x7b, 0xac, 0xe1, 0x07, 0xd3, 0x1f, 0x76, 0x1d, 0x67, 0x1d,
0x2f, 0x6a, 0x42, 0x9a, 0xf2, 0x9a, 0x46, 0x9b, 0x53, 0x9a, 0xfb, 0x5b,
0x62, 0x5b, 0xba, 0x4f, 0xcc, 0x3e, 0xd1, 0xd6, 0xea, 0xde, 0x7a, 0xfc,
0x47, 0xdb, 0x1f, 0x0f, 0x9c, 0x34, 0x3c, 0x59, 0x79, 0x4a, 0xf3, 0x54,
0xc9, 0x69, 0xda, 0xe9, 0x82, 0xd3, 0x93, 0x67, 0xf2, 0xcf, 0x8c, 0x9d,
0x95, 0x9d, 0x7d, 0x7e, 0x2e, 0xf9, 0xdc, 0x60, 0xdb, 0xa2, 0xb6, 0x7b,
0xe7, 0x63, 0xce, 0xdf, 0x6a, 0x0f, 0x6f, 0xef, 0xba, 0x10, 0x74, 0xe1,
0xd2, 0x45, 0xff, 0x8b, 0xe7, 0x3b, 0xbc, 0x3b, 0xce, 0x5c, 0xf2, 0xb8,
0x74, 0xf2, 0xb2, 0xdb, 0xe5, 0x13, 0x57, 0xb8, 0x57, 0x9a, 0xaf, 0x3a,
0x5f, 0x6d, 0xea, 0x74, 0xea, 0x3c, 0xfe, 0x93, 0xd3, 0x4f, 0xc7, 0xbb,
0x9c, 0xbb, 0x9a, 0xae, 0xb9, 0x5c, 0x6b, 0xb9, 0xee, 0x7a, 0xbd, 0xb5,
0x7b, 0x66, 0xf7, 0xe9, 0x1b, 0x9e, 0x37, 0xce, 0xdd, 0xf4, 0xbd, 0x79,
0xf1, 0x16, 0xff, 0xd6, 0xd5, 0x9e, 0x39, 0x3d, 0xdd, 0xbd, 0xf3, 0x7a,
0x6f, 0xf7, 0xc5, 0xf7, 0xf5, 0xdf, 0x16, 0xdd, 0x7e, 0x72, 0x27, 0xfd,
0xce, 0xcb, 0xbb, 0xd9, 0x77, 0x27, 0xee, 0xad, 0xbc, 0x4f, 0xbc, 0x5f,
0xf4, 0x40, 0xed, 0x41, 0xd9, 0x43, 0xdd, 0x87, 0xd5, 0x3f, 0x5b, 0xfe,
0xdc, 0xd8, 0xef, 0xdc, 0x7f, 0x6a, 0xc0, 0x77, 0xa0, 0xf3, 0xd1, 0xdc,
0x47, 0xf7, 0x06, 0x85, 0x83, 0xcf, 0xfe, 0x91, 0xf5, 0x8f, 0x0f, 0x43,
0x05, 0x8f, 0x99, 0x8f, 0xcb, 0x86, 0x0d, 0x86, 0xeb, 0x9e, 0x38, 0x3e,
0x39, 0x39, 0xe2, 0x3f, 0x72, 0xfd, 0xe9, 0xfc, 0xa7, 0x43, 0xcf, 0x64,
0xcf, 0x26, 0x9e, 0x17, 0xfe, 0xa2, 0xfe, 0xcb, 0xae, 0x17, 0x16, 0x2f,
0x7e, 0xf8, 0xd5, 0xeb, 0xd7, 0xce, 0xd1, 0x98, 0xd1, 0xa1, 0x97, 0xf2,
0x97, 0x93, 0xbf, 0x6d, 0x7c, 0xa5, 0xfd, 0xea, 0xc0, 0xeb, 0x19, 0xaf,
0xdb, 0xc6, 0xc2, 0xc6, 0x1e, 0xbe, 0xc9, 0x78, 0x33, 0x31, 0x5e, 0xf4,
0x56, 0xfb, 0xed, 0xc1, 0x77, 0xdc, 0x77, 0x1d, 0xef, 0xa3, 0xdf, 0x0f,
0x4f, 0xe4, 0x7c, 0x20, 0x7f, 0x28, 0xff, 0x68, 0xf9, 0xb1, 0xf5, 0x53,
0xd0, 0xa7, 0xfb, 0x93, 0x19, 0x93, 0x93, 0xff, 0x04, 0x03, 0x98, 0xf3,
0xfc, 0x63, 0x33, 0x2d, 0xdb, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52,
0x4d, 0x00, 0x00, 0x7a, 0x25, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, 0xf9,
0xff, 0x00, 0x00, 0x80, 0xe9, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea,
0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, 0x00, 0x17, 0x6f, 0x92, 0x5f, 0xc5,
0x46, 0x00, 0x00, 0x02, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec,
0x98, 0x4d, 0x4e, 0x02, 0x41, 0x10, 0x85, 0x3f, 0x8d, 0xdb, 0xb9, 0x80,
0x73, 0x01, 0x70, 0x2f, 0xee, 0x41, 0xf7, 0x72, 0x00, 0x0d, 0x7b, 0xc2,
0xde, 0xc4, 0xb5, 0x09, 0x7b, 0xc2, 0xde, 0xe0, 0x01, 0xd0, 0xbd, 0x5c,
0x00, 0x2e, 0xc0, 0x05, 0xe4, 0x00, 0xce, 0x01, 0x74, 0x53, 0x9d, 0x54,
0xda, 0xea, 0x99, 0x46, 0x51, 0x8c, 0xd6, 0x4b, 0x3a, 0x0c, 0xdd, 0x3d,
0x5d, 0x5d, 0xf5, 0xea, 0x2f, 0x73, 0x00, 0xbc, 0xe1, 0xd8, 0x1b, 0x0e,
0xdd, 0x04, 0x4e, 0x80, 0x13, 0xe0, 0x70, 0x02, 0x9c, 0x00, 0x87, 0x13,
0xe0, 0x04, 0x38, 0x9c, 0x00, 0x27, 0xc0, 0xe1, 0x04, 0x38, 0x01, 0x0e,
0x27, 0xe0, 0xdf, 0xe0, 0xc8, 0x9a, 0x6c, 0x01, 0x13, 0xa0, 0x34, 0xd6,
0x66, 0xc0, 0x58, 0x9e, 0xfb, 0xc0, 0x0d, 0x50, 0x18, 0xfb, 0x5e, 0x80,
0x11, 0xb0, 0xce, 0xb8, 0x44, 0x07, 0xb8, 0x4f, 0xac, 0x55, 0x22, 0x73,
0x9a, 0x71, 0xce, 0x50, 0x86, 0x96, 0x9d, 0xba, 0x63, 0x25, 0x7a, 0xcc,
0xe5, 0xff, 0x0d, 0x70, 0xdd, 0xa0, 0x47, 0x21, 0x76, 0xe9, 0x18, 0xfb,
0x96, 0xc0, 0x4a, 0xe4, 0x93, 0x38, 0x67, 0x0c, 0x2c, 0xa2, 0xf9, 0x03,
0xa2, 0xaf, 0xa1, 0x05, 0xf0, 0x9c, 0x30, 0x6a, 0xc0, 0x54, 0x84, 0xdd,
0x37, 0x18, 0xa4, 0x02, 0xce, 0xe5, 0xf7, 0xb3, 0x04, 0x04, 0xdc, 0x2a,
0x63, 0x59, 0xb8, 0x13, 0x63, 0x07, 0x2c, 0x80, 0x87, 0x8c, 0x73, 0x07,
0xc0, 0x69, 0x8d, 0xe1, 0xb4, 0x1e, 0x29, 0xe3, 0xe7, 0x10, 0x10, 0x70,
0x21, 0x64, 0x24, 0x53, 0x50, 0x5b, 0x8c, 0xbf, 0x06, 0x4e, 0xa2, 0x31,
0x92, 0x3d, 0xa7, 0x32, 0x42, 0x44, 0x9c, 0x18, 0x23, 0x78, 0x4c, 0x7b,
0x8b, 0x70, 0x5c, 0xd6, 0xc8, 0x3c, 0xce, 0x34, 0xfe, 0x42, 0x39, 0x52,
0xdd, 0x1d, 0x67, 0x86, 0x2e, 0xa3, 0x06, 0x3d, 0x82, 0xf1, 0xcf, 0x8c,
0x7d, 0x83, 0xc8, 0x41, 0x53, 0xf2, 0xca, 0x9c, 0x14, 0x04, 0xf0, 0x9a,
0xf0, 0x84, 0x9c, 0xb9, 0xd4, 0xfb, 0x4d, 0x68, 0x1b, 0x1e, 0x5b, 0x36,
0xc8, 0xd1, 0xc6, 0xaf, 0x12, 0x69, 0xb3, 0xfa, 0xc2, 0x9c, 0xa5, 0xc7,
0xc4, 0x98, 0x7b, 0x52, 0xcf, 0x97, 0x8a, 0x54, 0xad, 0x9b, 0x75, 0xde,
0xd1, 0x6f, 0x2a, 0x48, 0x45, 0x4d, 0x88, 0x57, 0x89, 0x9c, 0xdf, 0x8f,
0xde, 0x6f, 0xfd, 0xc0, 0x3d, 0xad, 0x3b, 0xae, 0x22, 0xa7, 0x29, 0x33,
0xf5, 0xf8, 0x55, 0x04, 0xac, 0x55, 0x81, 0x47, 0xa5, 0x88, 0x21, 0xd0,
0x8d, 0x6a, 0x40, 0x5f, 0xe5, 0xdb, 0xb1, 0x2a, 0xf6, 0x2d, 0x29, 0xa8,
0xdf, 0x89, 0x41, 0xa2, 0xc8, 0x5e, 0xca, 0xf3, 0x3c, 0x8a, 0x08, 0x80,
0x2b, 0xa0, 0x27, 0x7b, 0xa6, 0xbb, 0x20, 0x20, 0x30, 0xd9, 0xab, 0x49,
0x27, 0xdb, 0xa6, 0xa2, 0xc2, 0x08, 0x5d, 0xcb, 0xa3, 0xfb, 0x92, 0x7a,
0x72, 0x8a, 0xf3, 0x2e, 0x51, 0xc9, 0x1d, 0xbb, 0x86, 0x27, 0x6b, 0x8f,
0xdf, 0x48, 0x3d, 0x8b, 0x1d, 0xa9, 0x97, 0xdb, 0x86, 0xe6, 0x60, 0x2e,
0x6c, 0xb6, 0x6a, 0xc2, 0x7e, 0x9e, 0xd9, 0x86, 0x6a, 0x25, 0x86, 0x09,
0xc5, 0xa7, 0x7b, 0x36, 0x7e, 0x88, 0xb4, 0xbb, 0x44, 0xbb, 0xba, 0x8c,
0xd2, 0x50, 0x2e, 0x3e, 0xb4, 0xa1, 0xa5, 0x18, 0x76, 0x63, 0x28, 0x17,
0xaf, 0x15, 0x62, 0x10, 0xab, 0x65, 0xdd, 0x6c, 0x61, 0x9c, 0x52, 0x85,
0xaf, 0x85, 0x47, 0x09, 0x71, 0xbd, 0x6f, 0x6d, 0xf4, 0xd4, 0xf1, 0x1d,
0x5f, 0xc4, 0xf3, 0x56, 0x86, 0x47, 0x76, 0xd4, 0x5a, 0x29, 0x5d, 0xd6,
0x63, 0xd4, 0x22, 0x06, 0xc2, 0xf5, 0x5a, 0xc7, 0x88, 0x52, 0xb6, 0x94,
0xb7, 0xac, 0x23, 0xc0, 0xe1, 0x9f, 0x22, 0x9c, 0x00, 0x87, 0x13, 0xe0,
0x04, 0x38, 0x9c, 0x00, 0x27, 0xc0, 0xe1, 0x04, 0x38, 0x01, 0x0e, 0x27,
0xe0, 0x4f, 0xe3, 0x7d, 0x00, 0x51, 0xbe, 0x83, 0xcd, 0x57, 0x34, 0x65,
0x10, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
0x82,
};

View file

@ -84,35 +84,34 @@ TextureCache::~TextureCache()
void TextureCache::OnConfigChanged(VideoConfig& config)
{
if (!g_texture_cache)
goto skip_checks;
// TODO: Invalidating texcache is really stupid in some of these cases
if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples ||
config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay ||
config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center ||
config.bHiresTextures != backup_config.s_hires_textures)
if (g_texture_cache)
{
g_texture_cache->Invalidate();
// TODO: Invalidating texcache is really stupid in some of these cases
if (config.iSafeTextureCache_ColorSamples != backup_config.s_colorsamples ||
config.bTexFmtOverlayEnable != backup_config.s_texfmt_overlay ||
config.bTexFmtOverlayCenter != backup_config.s_texfmt_overlay_center ||
config.bHiresTextures != backup_config.s_hires_textures)
{
g_texture_cache->Invalidate();
if(g_ActiveConfig.bHiresTextures)
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
if(g_ActiveConfig.bHiresTextures)
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
SetHash64Function(g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
SetHash64Function(g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
}
// TODO: Probably shouldn't clear all render targets here, just mark them dirty or something.
if (config.bEFBCopyCacheEnable != backup_config.s_copy_cache_enable || // TODO: not sure if this is needed?
config.bCopyEFBToTexture != backup_config.s_copy_efb_to_texture ||
config.bCopyEFBScaled != backup_config.s_copy_efb_scaled ||
config.bEFBCopyEnable != backup_config.s_copy_efb ||
config.iEFBScale != backup_config.s_efb_scale)
{
g_texture_cache->ClearRenderTargets();
}
}
// TODO: Probably shouldn't clear all render targets here, just mark them dirty or something.
if (config.bEFBCopyCacheEnable != backup_config.s_copy_cache_enable || // TODO: not sure if this is needed?
config.bCopyEFBToTexture != backup_config.s_copy_efb_to_texture ||
config.bCopyEFBScaled != backup_config.s_copy_efb_scaled ||
config.bEFBCopyEnable != backup_config.s_copy_efb ||
config.iEFBScale != backup_config.s_efb_scale)
{
g_texture_cache->ClearRenderTargets();
}
skip_checks:
backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples;
backup_config.s_copy_efb_to_texture = config.bCopyEFBToTexture;
backup_config.s_copy_efb_scaled = config.bCopyEFBScaled;
@ -301,14 +300,30 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level)
entry->Save(szTemp, level);
}
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
u32 address, unsigned int width, unsigned int height, int texformat,
unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem)
static u32 CalculateLevelSize(u32 level_0_size, u32 level)
{
return (level_0_size + ((1 << level) - 1)) >> level;
}
// Used by TextureCache::Load
static TextureCache::TCacheEntryBase* ReturnEntry(unsigned int stage, TextureCache::TCacheEntryBase* entry)
{
entry->frameCount = frameCount;
entry->Bind(stage);
GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true);
return entry;
}
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
u32 const address, unsigned int width, unsigned int height, int const texformat,
unsigned int const tlutaddr, int const tlutfmt, bool const use_mipmaps, unsigned int maxlevel, bool const from_tmem)
{
if (0 == address)
return NULL;
// TexelSizeInNibbles(format)*width*height/16;
// TexelSizeInNibbles(format) * width * height / 16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
@ -317,11 +332,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
const unsigned int nativeW = width;
const unsigned int nativeH = height;
bool using_custom_texture = false;
bool using_custom_lods = false;
u32 texID = address;
u64 tex_hash = TEXHASH_INVALID; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
// Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
u64 tex_hash = TEXHASH_INVALID;
u64 tlut_hash = TEXHASH_INVALID;
u32 full_format = texformat;
@ -332,9 +345,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
full_format = texformat | (tlutfmt << 16);
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
u8* src_data;
if (from_tmem) src_data = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE];
else src_data = Memory::GetPointer(address);
const u8* src_data;
if (from_tmem)
src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE];
else
src_data = Memory::GetPointer(address);
// TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data from the low tmem bank than it should)
tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
@ -356,6 +372,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
tex_hash ^= tlut_hash;
}
// D3D doesn't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,1x1, so we limit the mipmap count to 6 there
while (g_ActiveConfig.backend_info.bUseMinimalMipCount && max(expandedWidth, expandedHeight) >> maxlevel == 0)
--maxlevel;
TCacheEntryBase *entry = textures[texID];
if (entry)
{
@ -369,15 +390,17 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
{
entry->type = TCET_EC_VRAM;
// TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
goto return_entry;
// TODO: Print a warning if the format changes! In this case,
// we could reinterpret the internal texture object data to the new pixel format
// (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
return ReturnEntry(stage, entry);
}
// 2. b) For normal textures, all texture parameters need to match
if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
entry->num_mipmaps > maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
{
goto return_entry;
return ReturnEntry(stage, entry);
}
// 3. If we reach this line, we'll have to upload the new texture data to VRAM.
@ -385,7 +408,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
//
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches...
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps > maxlevel)
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height
&& full_format == entry->format && entry->num_mipmaps > maxlevel)
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
{
// reuse the texture
@ -398,9 +422,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
}
}
bool using_custom_texture = false;
if (g_ActiveConfig.bHiresTextures)
{
// This function may modify width/height.
pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height);
if (pcfmt != PC_TEX_FMT_NONE)
{
@ -431,111 +457,100 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
}
}
unsigned int texLevels;
bool use_native_mips;
texLevels = use_mipmaps ? (maxlevel + 1) : 1;
using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1;
u32 texLevels = use_mipmaps ? (maxlevel + 1) : 1;
const bool using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
// Only load native mips if their dimensions fit to our virtual texture dimensions
const bool use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH);
texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1; // TODO: Should be forced to 1 for non-pow2 textures (e.g. efb copies with automatically adjusted IR)
// create the entry/texture
if (NULL == entry) {
if (NULL == entry)
{
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
// Sometimes, we can get around recreating a texture if only the number of mip levels changes
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
// TODO: D3D9 doesn't support min_lod. We should add a workaround for that here!
// TODO: This is the wrong value. We should be storing the number of levels our actual texture has.
// But that will currently make the above "existing entry" tests fail as "texLevels" is not calculated until after.
// Currently, we might try to reuse a texture which appears to have more levels than actual, maybe..
entry->num_mipmaps = maxlevel + 1;
entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
}
else
{
// load texture (CreateTexture also loads level 0)
entry->Load(width, height, expandedWidth, 0);
}
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
entry->SetDimensions(nativeW, nativeH, width, height);
entry->hash = tex_hash;
if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_EC_DYNAMIC;
else entry->type = TCET_NORMAL;
// load texture
entry->Load(width, height, expandedWidth, 0);
if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture)
entry->type = TCET_EC_DYNAMIC;
else
entry->type = TCET_NORMAL;
if (g_ActiveConfig.bDumpTextures && !using_custom_texture)
DumpTexture(entry, 0);
u32 level = 1;
// load mips - TODO: Loading mipmaps from tmem is untested!
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && use_native_mips)
if (pcfmt != PC_TEX_FMT_NONE)
{
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
unsigned int level = 1;
unsigned int mipWidth = (width + 1) >> 1;
unsigned int mipHeight = (height + 1) >> 1;
u8* ptr_even = NULL, *ptr_odd = NULL;
if (from_tmem)
if (use_native_mips)
{
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
src_data += texture_size;
const u8* ptr_even = NULL;
const u8* ptr_odd = NULL;
if (from_tmem)
{
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
}
for (; level != texLevels; ++level)
{
const u32 mip_width = CalculateLevelSize(width, level);
const u32 mip_height = CalculateLevelSize(height, level);
const u32 expanded_mip_width = (mip_width + bsw) & (~bsw);
const u32 expanded_mip_height = (mip_height + bsh) & (~bsh);
const u8*& mip_src_data = from_tmem
? ((level % 2) ? ptr_odd : ptr_even)
: src_data;
TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
entry->Load(mip_width, mip_height, expanded_mip_width, level);
if (g_ActiveConfig.bDumpTextures)
DumpTexture(entry, level);
}
}
src_data += texture_size;
while ((mipHeight || mipWidth) && (level < texLevels))
else if (using_custom_lods)
{
u8** ptr;
if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even;
else ptr = &src_data;
for (; level != texLevels; ++level)
{
unsigned int mip_width = CalculateLevelSize(width, level);
unsigned int mip_height = CalculateLevelSize(height, level);
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
expandedWidth = (currentWidth + bsw) & (~bsw);
expandedHeight = (currentHeight + bsh) & (~bsh);
TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
entry->Load(currentWidth, currentHeight, expandedWidth, level);
if (g_ActiveConfig.bDumpTextures)
DumpTexture(entry, level);
*ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
mipWidth >>= 1;
mipHeight >>= 1;
++level;
}
}
else if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && using_custom_lods)
{
unsigned int level = 1;
unsigned int mipWidth = (width + 1) >> 1;
unsigned int mipHeight = (height + 1) >> 1;
while ((mipHeight || mipWidth) && (level < texLevels))
{
unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight);
entry->Load(currentWidth, currentHeight, currentWidth, level);
mipWidth >>= 1;
mipHeight >>= 1;
++level;
LoadCustomTexture(tex_hash, texformat, level, mip_width, mip_height);
entry->Load(mip_width, mip_height, mip_width, level);
}
}
}
INCSTAT(stats.numTexturesCreated);
SETSTAT(stats.numTexturesAlive, textures.size());
return_entry:
entry->frameCount = frameCount;
entry->Bind(stage);
GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true);
return entry;
return ReturnEntry(stage, entry);
}
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,

View file

@ -692,7 +692,7 @@ inline void SetOpenMPThreadCount(int width, int height)
if (g_ActiveConfig.bOMPDecoder && width > 127 && height > 127)
{
// don't span to many threads they will kill the rest of the emu :)
omp_set_num_threads((cpu_info.num_cores + 2) / 3);
omp_set_num_threads((omp_get_num_procs() + 2) / 3);
}
else
{

View file

@ -42,6 +42,7 @@ VideoConfig::VideoConfig()
// disable all features by default
backend_info.APIType = API_NONE;
backend_info.bUseRGBATextures = false;
backend_info.bUseMinimalMipCount = false;
backend_info.bSupports3DVision = false;
}

View file

@ -157,6 +157,7 @@ struct VideoConfig
std::vector<std::string> PPShaders; // post-processing shaders
bool bUseRGBATextures; // used for D3D11 in TextureCache
bool bUseMinimalMipCount;
bool bSupports3DVision;
bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL
bool bSupportsFormatReinterpretation;