Merge branch 'master' into GLSL-master

Conflicts:
	CMakeLists.txt
	Source/Core/DolphinWX/Dolphin.vcxproj
	Source/Core/DolphinWX/Src/GLInterface/WX.cpp
	Source/Core/DolphinWX/Src/GLInterface/WX.h
	Source/Core/VideoCommon/Src/TextureCacheBase.cpp
	Source/Core/VideoCommon/Src/TextureCacheBase.h
	Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp
	Source/Plugins/Plugin_VideoDX11/Src/TextureCache.h
	Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp
	Source/Plugins/Plugin_VideoDX9/Src/TextureCache.h
	Source/Plugins/Plugin_VideoOGL/Src/Render.cpp
	Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/TextureCache.h
	Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp

damn mipmap_fixes ...
This commit is contained in:
degasus 2013-02-18 18:49:20 +01:00
commit a629dea4dc
184 changed files with 7637 additions and 6605 deletions

View file

@ -232,70 +232,70 @@ float passive_lock(float x)
void matrix_decode(const float *in, const int k, const int il,
const int ir, bool decode_rear,
const int dlbuflen,
float l_fwr, float r_fwr,
float lpr_fwr, float lmr_fwr,
float *adapt_l_gain, float *adapt_r_gain,
float *adapt_lpr_gain, float *adapt_lmr_gain,
float *lf, float *rf, float *lr,
float *rr, float *cf)
const int _dlbuflen,
float _l_fwr, float _r_fwr,
float _lpr_fwr, float _lmr_fwr,
float *_adapt_l_gain, float *_adapt_r_gain,
float *_adapt_lpr_gain, float *_adapt_lmr_gain,
float *_lf, float *_rf, float *_lr,
float *_rr, float *_cf)
{
static const float M9_03DB = 0.3535533906f;
static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */
static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */
static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */
const int kr = (k + olddelay) % dlbuflen;
float l_gain = (l_fwr + r_fwr) / (1 + l_fwr + l_fwr);
float r_gain = (l_fwr + r_fwr) / (1 + r_fwr + r_fwr);
const int kr = (k + olddelay) % _dlbuflen;
float l_gain = (_l_fwr + _r_fwr) / (1 + _l_fwr + _l_fwr);
float r_gain = (_l_fwr + _r_fwr) / (1 + _r_fwr + _r_fwr);
/* The 2nd axis has strong gain fluctuations, and therefore require
limits. The factor corresponds to the 1 / amplification of (Lt
- Rt) when (Lt, Rt) is strongly correlated. (e.g. during
dialogues). It should be bigger than -12 dB to prevent
distortion. */
float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ? lmr_fwr : M9_03DB * lpr_fwr;
float lpr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lpr_fwr + lpr_fwr);
float lmr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
float lmr_unlim_gain = (lpr_fwr + lmr_fwr) / (1 + lmr_fwr + lmr_fwr);
float lmr_lim_fwr = _lmr_fwr > M9_03DB * _lpr_fwr ? _lmr_fwr : M9_03DB * _lpr_fwr;
float lpr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + _lpr_fwr + _lpr_fwr);
float lmr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
float lmr_unlim_gain = (_lpr_fwr + _lmr_fwr) / (1 + _lmr_fwr + _lmr_fwr);
float lpr, lmr;
float l_agc, r_agc, lpr_agc, lmr_agc;
float f, d_gain, c_gain, c_agc_cfk;
/*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
/* AGC adaption */
d_gain = (fabs(l_gain - *adapt_l_gain) + fabs(r_gain - *adapt_r_gain)) * 0.5f;
d_gain = (fabs(l_gain - *_adapt_l_gain) + fabs(r_gain - *_adapt_r_gain)) * 0.5f;
f = d_gain * (1.0f / MATAGCTRIG);
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
*adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
*adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
*_adapt_l_gain = (1 - f) * *_adapt_l_gain + f * l_gain;
*_adapt_r_gain = (1 - f) * *_adapt_r_gain + f * r_gain;
/* Matrix */
l_agc = in[il] * passive_lock(*adapt_l_gain);
r_agc = in[ir] * passive_lock(*adapt_r_gain);
cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
l_agc = in[il] * passive_lock(*_adapt_l_gain);
r_agc = in[ir] * passive_lock(*_adapt_r_gain);
_cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
if (decode_rear)
{
lr[kr] = rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
_lr[kr] = _rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
/* Stereo rear channel is steered with the same AGC steering as
the decoding matrix. Note this requires a fast updating AGC
at the order of 20 ms (which is the case here). */
lr[kr] *= (l_fwr + l_fwr) / (1 + l_fwr + r_fwr);
rr[kr] *= (r_fwr + r_fwr) / (1 + l_fwr + r_fwr);
_lr[kr] *= (_l_fwr + _l_fwr) / (1 + _l_fwr + _r_fwr);
_rr[kr] *= (_r_fwr + _r_fwr) / (1 + _l_fwr + _r_fwr);
}
/*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
lpr = (in[il] + in[ir]) * (float)M_SQRT1_2;
lmr = (in[il] - in[ir]) * (float)M_SQRT1_2;
/* AGC adaption */
d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
d_gain = fabs(lmr_unlim_gain - *_adapt_lmr_gain);
f = d_gain * (1.0f / MATAGCTRIG);
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
*adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
*adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
*_adapt_lpr_gain = (1 - f) * *_adapt_lpr_gain + f * lpr_gain;
*_adapt_lmr_gain = (1 - f) * *_adapt_lmr_gain + f * lmr_gain;
/* Matrix */
lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
lpr_agc = lpr * passive_lock(*_adapt_lpr_gain);
lmr_agc = lmr * passive_lock(*_adapt_lmr_gain);
_lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
_rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
/*** CENTER FRONT CANCELLATION ***/
/* A heuristic approach exploits that Lt + Rt gain contains the
@ -303,16 +303,16 @@ void matrix_decode(const float *in, const int k, const int il,
the front and rear "cones" to concentrate Lt + Rt to C and
introduce Lt - Rt in L, R. */
/* 0.67677 is the empirical lower bound for lpr_gain. */
c_gain = 8 * (*adapt_lpr_gain - 0.67677f);
c_gain = 8 * (*_adapt_lpr_gain - 0.67677f);
c_gain = c_gain > 0 ? c_gain : 0;
/* c_gain should not be too high, not even reaching full
cancellation (~ 0.50 - 0.55 at current AGC implementation), or
the center will sound too narrow. */
c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
c_agc_cfk = c_gain * cf[k];
lf[k] -= c_agc_cfk;
rf[k] -= c_agc_cfk;
cf[k] += c_agc_cfk + c_agc_cfk;
c_agc_cfk = c_gain * _cf[k];
_lf[k] -= c_agc_cfk;
_rf[k] -= c_agc_cfk;
_cf[k] += c_agc_cfk + c_agc_cfk;
}
void dpl2decode(float *samples, int numsamples, float *out)

View file

@ -92,7 +92,7 @@ public:
std::mutex& MixerCritical() { return m_csMixing; }
volatile float GetCurrentSpeed() const { return m_speed; }
float GetCurrentSpeed() const { return m_speed; }
void UpdateSpeed(volatile float val) { m_speed = val; }
protected:

View file

@ -316,7 +316,7 @@ void OpenALStream::SoundLoop()
if (iBuffersFilled == numBuffers)
{
alSourcePlay(uiSource);
ALenum err = alGetError();
err = alGetError();
if (err != 0)
{
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
@ -328,7 +328,7 @@ void OpenALStream::SoundLoop()
{
// Buffer underrun occurred, resume playback
alSourcePlay(uiSource);
ALenum err = alGetError();
err = alGetError();
if (err != 0)
{
ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err);

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);
@ -773,6 +775,24 @@ IOFile::~IOFile()
Close();
}
IOFile::IOFile(IOFile&& other)
: m_file(NULL), m_good(true)
{
Swap(other);
}
IOFile& IOFile::operator=(IOFile other)
{
Swap(other);
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

@ -150,7 +150,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();
@ -158,6 +158,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();
@ -212,6 +217,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

@ -43,7 +43,8 @@ void MemArena::GrabLowMemSpace(size_t size)
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
unlink(ram_temp_file);
ftruncate(fd, size);
if (ftruncate(fd, size) < 0)
ERROR_LOG(MEMMAP, "Failed to allocate low memory space");
return;
#endif
}

View file

@ -117,7 +117,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
void* ptr = _aligned_malloc(size,alignment);
#else
void* ptr = NULL;
posix_memalign(&ptr, alignment, size);
if (posix_memalign(&ptr, alignment, size) != 0)
ERROR_LOG(MEMMAP, "Failed to allocate aligned memory");
;
#endif

View file

@ -69,7 +69,8 @@ std::string StringFromFormat(const char* format, ...)
delete[] buf;
#else
va_start(args, format);
vasprintf(&buf, format, args);
if (vasprintf(&buf, format, args) < 0)
ERROR_LOG(COMMON, "Unable to allocate memory for string");
va_end(args);
std::string temp = buf;

View file

@ -55,7 +55,7 @@ namespace BootManager
struct ConfigCache
{
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bDisableWiimoteSpeaker, bHLE_BS2;
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
int iTLBHack, iCPUCore;
std::string strBackend;
};
@ -98,7 +98,6 @@ bool BootCore(const std::string& _rFilename)
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
config_cache.bDSPHLE = StartUp.bDSPHLE;
config_cache.bDisableWiimoteSpeaker = StartUp.bDisableWiimoteSpeaker;
config_cache.strBackend = StartUp.m_strVideoBackend;
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
@ -113,7 +112,6 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
game_ini.Get("Wii", "DisableWiimoteSpeaker",&StartUp.bDisableWiimoteSpeaker, StartUp.bDisableWiimoteSpeaker);
game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str());
game_ini.Get("Core", "CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore);
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
@ -173,7 +171,6 @@ void Stop()
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
StartUp.bDSPHLE = config_cache.bDSPHLE;
StartUp.bDisableWiimoteSpeaker = config_cache.bDisableWiimoteSpeaker;
StartUp.m_strVideoBackend = config_cache.strBackend;
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;

View file

@ -51,8 +51,8 @@ SCoreStartupParameter::SCoreStartupParameter()
bRunCompareServer(false), bRunCompareClient(false),
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
bFastDiscSpeed(false),
SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false),
bConfirmStop(false), bHideCursor(false),
SelectedLanguage(0), bWii(false),
bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
iRenderWindowXPos(-1), iRenderWindowYPos(-1),
iRenderWindowWidth(640), iRenderWindowHeight(480),
@ -99,8 +99,6 @@ void SCoreStartupParameter::LoadDefaults()
bJITPairedOff = false;
bJITSystemRegistersOff = false;
bDisableWiimoteSpeaker = false;
m_strName = "NONE";
m_strUniqueID = "00000000";
}

View file

@ -121,7 +121,6 @@ struct SCoreStartupParameter
int SelectedLanguage;
bool bWii;
bool bDisableWiimoteSpeaker;
// Interface settings
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages;

View file

@ -171,9 +171,9 @@ bool InstallCodeHandler()
Memory::Write_U8(1, 0x80001807);
// Invalidate the icache
for (unsigned int i = 0; i < data.length(); i += 32)
for (unsigned int j = 0; j < data.length(); j += 32)
{
PowerPC::ppcState.iCache.Invalidate(0x80001800 + i);
PowerPC::ppcState.iCache.Invalidate(0x80001800 + j);
}
return true;
}

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

@ -78,7 +78,7 @@ private:
virtual void TransferByte(u8 &_uByte);
bool IsWriteCommand() const { return !!(m_uAddress & (1 << 31)); }
const u32 CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; }
u32 CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; }
void LoadFileToIPL(std::string filename, u32 offset);
};

View file

@ -251,12 +251,11 @@ void Init()
// Now the 1500 is a pure assumption
// We need to figure out the real frequency though
// FIXME: does Wiimote Speaker support really require a different interval? (issue 4608)
const int interval = SConfig::GetInstance().m_LocalCoreStartupParameter.
bDisableWiimoteSpeaker ? 15000 : 4000;
// FYI, WII_IPC_HLE_Interface::Update is also called in WII_IPCInterface::Write32
const int freq = 1500;
const int fields = SConfig::GetInstance().m_LocalCoreStartupParameter.
bVBeam ? 2 : 1;
IPC_HLE_PERIOD = GetTicksPerSecond() / (interval * fields);
IPC_HLE_PERIOD = GetTicksPerSecond() / (freq * fields);
}
else
{

View file

@ -144,8 +144,8 @@ void Preset(bool _bNTSC)
m_HorizontalStepping.FbSteps = 40;
m_HorizontalStepping.FieldSteps = 40;
m_HBeamPos = 0;
m_VBeamPos = 0;
m_HBeamPos = -1; // NTSC-U N64 VC games check for a non-zero HBeamPos
m_VBeamPos = 0; // RG4JC0 checks for a zero VBeamPos
// 54MHz, capable of progressive scan
m_Clock = Core::g_CoreStartupParameter.bProgressive;

View file

@ -221,6 +221,7 @@ void Write32(const u32 _Value, const u32 _Address)
break;
}
WII_IPC_HLE_Interface::Update();
UpdateInterrupts();
}

View file

@ -41,6 +41,13 @@ inline double round(double x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
#include "../../Movie.h"
namespace
{
// :)
auto const TAU = 6.28318530717958647692;
auto const PI = TAU / 2.0;
}
namespace WiimoteEmu
{

View file

@ -30,13 +30,6 @@
#include <vector>
#include <queue>
namespace
{
// :)
auto const TAU = 6.28318530717958647692;
auto const PI = TAU / 2.0;
}
// Registry sizes
#define WIIMOTE_EEPROM_SIZE (16*1024)
#define WIIMOTE_EEPROM_FREE_SIZE 0x1700

View file

@ -184,7 +184,7 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes)
bool found = false;
for(int i = 0; i < MAX_WIIMOTES; i++)
{
if(wm[i] && strcmp(wm[i]->devicepath, detail_data->DevicePath) == 0)
if(wm[i] && (wm[i]->devicepath == detail_data->DevicePath))
{
found = true;
break;
@ -210,7 +210,7 @@ int FindWiimotes(Wiimote** wm, int max_wiimotes)
for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k);
wm[k] = new Wiimote(k);
wm[k]->dev_handle = dev;
memcpy(wm[k]->devicepath, detail_data->DevicePath, 197);
wm[k]->devicepath = detail_data->DevicePath;
if (!wm[k]->Connect())
{
@ -240,7 +240,7 @@ bool Wiimote::Connect()
if (!dev_handle)
{
dev_handle = CreateFile(devicepath,
dev_handle = CreateFile(devicepath.c_str(),
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

View file

@ -181,23 +181,23 @@ bool Wiimote::Read()
bool Wiimote::Write()
{
Report rpt;
bool audio_written = false;
if (m_audio_reports.Pop(rpt))
if (last_audio_report.GetTimeDifference() > 5 && m_audio_reports.Pop(rpt))
{
IOWrite(rpt.first, rpt.second);
last_audio_report.Update();
delete[] rpt.first;
audio_written = true;
return true;
}
if (m_write_reports.Pop(rpt))
else if (m_write_reports.Pop(rpt))
{
IOWrite(rpt.first, rpt.second);
delete[] rpt.first;
return true;
}
}
return audio_written;
return false;
}
// Returns the next report that should be sent
@ -319,14 +319,9 @@ void Wiimote::ThreadFunc()
while (Write()) {}
Common::SleepCurrentThread(1);
#else
bool read = false;
while (Write() || (read = true, IsOpen() && Read()))
{
if (m_audio_reports.Size() && !read)
Read();
Common::SleepCurrentThread(m_audio_reports.Size() ? 5 : 2);
read = false;
}
bool const did_something = Write() || Read();
if (!did_something)
Common::SleepCurrentThread(1);
#endif
}
}

View file

@ -25,6 +25,7 @@
#include "ChunkFile.h"
#include "Thread.h"
#include "FifoQueue.h"
#include "Timer.h"
#include "../Wiimote.h"
#include "../WiimoteEmu/WiimoteEmu.h"
@ -77,7 +78,7 @@ public:
void Close();
#elif defined(_WIN32)
char devicepath[255]; // Unique wiimote reference
std::string devicepath; // Unique wiimote reference
//ULONGLONG btaddr; // Bluetooth address
HANDLE dev_handle; // HID handle
OVERLAPPED hid_overlap; // Overlap handle
@ -103,6 +104,8 @@ private:
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
Common::FifoQueue<Report> m_audio_reports;
Common::Timer last_audio_report;
};
extern std::mutex g_refresh_lock;

View file

@ -58,6 +58,8 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC
#include "../HW/WII_IPC.h"
#include "../Debugger/Debugger_SymbolMap.h"
#include "../PowerPC/PowerPC.h"
#include "../HW/SystemTimers.h"
#include "CoreTiming.h"
namespace WII_IPC_HLE_Interface
@ -80,8 +82,19 @@ typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc
static int enque_reply;
static u64 last_reply_time;
void EnqueReplyCallback(u64 userdata, int)
{
reply_queue.push_back(userdata);
}
void Init()
{
enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
CWII_IPC_HLE_Device_es::m_ContentFile = "";
u32 i;
@ -152,6 +165,7 @@ void Reset(bool _bHard)
}
request_queue.clear();
reply_queue.clear();
last_reply_time = 0;
}
void Shutdown()
@ -235,6 +249,7 @@ void DoState(PointerWrap &p)
{
p.Do(request_queue);
p.Do(reply_queue);
p.Do(last_reply_time);
TDeviceMap::const_iterator itr;
@ -338,7 +353,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)
@ -382,7 +397,7 @@ void ExecuteCommand(u32 _Address)
}
else
{
IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName);
pDevice = CreateFileIO(DeviceID, DeviceName);
CmdSuccess = pDevice->Open(_Address, Mode);
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
@ -394,6 +409,7 @@ void ExecuteCommand(u32 _Address)
else
{
delete pDevice;
pDevice = NULL;
}
}
@ -424,7 +440,10 @@ void ExecuteCommand(u32 _Address)
// Don't delete hardware
if (!pDevice->IsHardware())
{
delete pDevice;
pDevice = NULL;
}
}
else
{
@ -503,8 +522,19 @@ void ExecuteCommand(u32 _Address)
if (CmdSuccess)
{
// Ensure replies happen in order, fairly ugly
// Without this, tons of games fail now that DI commads have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
if (ticks_til_last_reply > 0)
reply_delay = ticks_til_last_reply;
last_reply_time = CoreTiming::GetTicks() + reply_delay;
// Generate a reply to the IPC command
EnqReply(_Address);
EnqReply(_Address, reply_delay);
}
else
{
@ -526,9 +556,9 @@ void EnqRequest(u32 _Address)
}
// Called when IOS module has some reply
void EnqReply(u32 _Address)
void EnqReply(u32 _Address, int cycles_in_future)
{
reply_queue.push_back(_Address);
CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
}
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp

View file

@ -62,7 +62,7 @@ void UpdateDevices();
void ExecuteCommand(u32 _Address);
void EnqRequest(u32 _Address);
void EnqReply(u32 _Address);
void EnqReply(u32 _Address, int cycles_in_future = 0);
enum ECommandType
{

View file

@ -95,6 +95,8 @@ public:
virtual bool IOCtlV (u32) { UNIMPLEMENTED_CMD(IOCtlV) }
#undef UNIMPLEMENTED_CMD
virtual int GetCmdDelay(u32) { return 0; }
virtual u32 Update() { return 0; }
virtual bool IsHardware() { return m_Hardware; }

View file

@ -28,6 +28,7 @@
#include "VolumeCreator.h"
#include "Filesystem.h"
#include "LogManager.h"
#include "../HW/SystemTimers.h"
#include "../../DiscIO/Src/FileMonitor.h"
@ -460,3 +461,45 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
// i dunno but prolly 1 is okay all the time :)
return 1;
}
int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
{
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
u32 Command = Memory::Read_U32(BufferIn) >> 24;
// Hacks below
switch (Command)
{
case DVDLowRead:
case DVDLowUnencryptedRead:
{
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 (ok, probably not true)
return SystemTimers::GetTicksPerSecond() / 975000 * Size;
break;
}
case DVDLowClearCoverInterrupt:
// Less than ~1/155th of a second hangs Oregon Trail at "loading wheel".
// More than ~1/140th of a second hangs Resident Evil Archives: Resident Evil Zero.
return SystemTimers::GetTicksPerSecond() / 146;
break;
// case DVDLowAudioBufferConfig:
// case DVDLowInquiry:
// case DVDLowReadDiskID:
// case DVDLowWaitForCoverClose:
// case DVDLowGetCoverReg:
// case DVDLowGetCoverStatus:
// case DVDLowReset:
// case DVDLowClosePartition:
default:
// ranom numbers here!
// More than ~1/2000th of a second hangs DKCR with DSP HLE, maybe.
return SystemTimers::GetTicksPerSecond() / 15000;
break;
}
}

View file

@ -38,6 +38,8 @@ public:
bool IOCtl(u32 _CommandAddress);
bool IOCtlV(u32 _CommandAddress);
int GetCmdDelay(u32);
private:

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,55 +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 u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
const u32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
if (OpenFile())
if (auto file = OpenFile())
{
ReturnValue = FS_RESULT_FATAL;
const u64 fileSize = m_pFileHandle.GetSize();
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){
switch (Mode)
{
case 0:
{
if (SeekPosition <= fileSize)
@ -230,7 +212,6 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
break;
}
}
CloseFile();
}
else
{
@ -248,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;
}
@ -269,7 +250,6 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
}
}
CloseFile();
}
else
{
@ -288,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
{
@ -329,9 +308,9 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
{
case 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, "FileIO: ISFS_IOCTL_GETFILESTATS");
@ -339,7 +318,6 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
Memory::Write_U32(m_FileLength, BufferOut);
Memory::Write_U32(m_SeekPos, BufferOut+4);
CloseFile();
}
else
{
@ -365,30 +343,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

@ -26,6 +26,7 @@
#include "FileUtil.h"
#include "NandPaths.h"
#include "ChunkFile.h"
#include "../HW/SystemTimers.h"
#include "../VolumeHandler.h"
@ -427,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);
}
@ -499,6 +500,13 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B
return FS_RESULT_FATAL;
}
int CWII_IPC_HLE_Device_fs::GetCmdDelay(u32)
{
// ~1/1000th of a second is too short and causes hangs in Wii Party
// Play it safe at 1/500th
return SystemTimers::GetTicksPerSecond() / 500;
}
void CWII_IPC_HLE_Device_fs::DoState(PointerWrap& p)
{
DoStateShared(p);

View file

@ -55,6 +55,8 @@ public:
virtual bool IOCtl(u32 _CommandAddress);
virtual bool IOCtlV(u32 _CommandAddress);
virtual int GetCmdDelay(u32);
private:

View file

@ -336,23 +336,23 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
pWiiMote->ExecuteL2capCmd(_pData, _Size);
}
// Here we send ACL packets to CPU. They will consist of header + data.
// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041.
// ---------------------------------------------------
// AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately
// rather than enqueue it to some other memory
// But...the only exception comes from the Wiimote_Plugin
void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle)
{
m_PacketCount[_ConnectionHandle & 0xff]++;
// I don't think this makes sense or should be necessary
// m_PacketCount refers to "completed" packets and is not related to some buffer size, yes?
#if 0
if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num)
{
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow");
m_PacketCount[_ConnectionHandle & 0xff] = m_acl_pkts_num;
}
#endif
}
// Here we send ACL packets to CPU. They will consist of header + data.
// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041.
void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size)
{
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle);
@ -374,8 +374,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u
}
else
{
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, "
"queueing(%d)...", m_acl_pool.GetWritePos());
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queueing...");
m_acl_pool.Store(_pData, _Size, _ConnectionHandle);
}
}
@ -486,18 +485,8 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
}
}
// The Real Wiimote sends report every ~6.66ms (150 Hz).
// However, we don't actually reach here at dependable intervals, so we
// instead just timeslice in such a way that makes the stack think we have
// perfect "radio quality" (WPADGetRadioSensitivity) and yet still have some
// idle time.
// Somehow, Dolphin's Wiimote Speaker support requires using an update interval
// of 5ms (200 Hz) for its output to work. This increased frequency tends to
// fill the ACL queue (even) quicker than it can be processed by Dolphin,
// especially during simultaneous requests involving many (emulated) Wiimotes...
// Thus, we only use that interval when the option is enabled. See issue 4608.
const u64 interval = SystemTimers::GetTicksPerSecond() / (SConfig::GetInstance().
m_LocalCoreStartupParameter.bDisableWiimoteSpeaker ? 150 : 200);
// The Real Wiimote sends report every ~5ms (200 Hz).
const u64 interval = SystemTimers::GetTicksPerSecond() / 200;
const u64 each_wiimote_interval = interval / m_WiiMotes.size();
const u64 now = CoreTiming::GetTicks();
@ -518,25 +507,47 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
return packet_transferred;
}
void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, const u16 conn_handle)
{
if (m_queue.size() >= 100)
{
// Many simultaneous exchanges of ACL packets tend to cause the queue to fill up.
ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue size reached 100 - current packet will be dropped!");
return;
}
_dbg_assert_msg_(WII_IPC_WIIMOTE,
size < m_acl_pkt_size, "acl packet too large for pool");
m_queue.push_back(Packet());
auto& packet = m_queue.back();
std::copy(data, data + size, packet.data);
packet.size = size;
packet.conn_handle = conn_handle;
}
void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint)
{
const u8 *data = m_pool + m_acl_pkt_size * m_read_ptr;
const u16 size = m_info[m_read_ptr].size;
const u16 conn_handle = m_info[m_read_ptr].conn_handle;
auto& packet = m_queue.front();
const u8* const data = packet.data;
const u16 size = packet.size;
const u16 conn_handle = packet.conn_handle;
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from "
"queue(%d) to %08x", GetReadPos(), endpoint.m_address);
"queue to %08x", endpoint.m_address);
hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer);
pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT);
pHeader->length = size;
// Write the packet to the buffer
memcpy((u8*)pHeader + sizeof(hci_acldata_hdr_t), data, pHeader->length);
std::copy(data, data + size, (u8*)pHeader + sizeof(hci_acldata_hdr_t));
endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size);
m_read_ptr = (m_read_ptr + 1) % m_acl_pkts_num;
m_queue.pop_front();
WII_IPC_HLE_Interface::EnqReply(endpoint.m_address);
endpoint.Invalidate();

View file

@ -17,9 +17,11 @@
#pragma once
#include "hci.h"
#include <algorithm>
#include <vector>
#include <queue>
#include "hci.h"
#include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device.h"
#include "WII_IPC_HLE_WiiMote.h"
@ -168,70 +170,33 @@ private:
class ACLPool
{
u8 m_pool[m_acl_pkt_size * m_acl_pkts_num];
int m_read_ptr;
int m_write_ptr;
struct
struct Packet
{
u8 data[m_acl_pkt_size];
u16 size;
u16 conn_handle;
} m_info[m_acl_pkts_num];
};
std::deque<Packet> m_queue;
public:
ACLPool()
: m_read_ptr(0)
, m_write_ptr(0)
: m_queue()
{}
void Store(const u8* data, const u16 size, const u16 conn_handle)
{
_dbg_assert_msg_(WII_IPC_WIIMOTE,
size < m_acl_pkt_size, "acl packet too large for pool");
const int next_write_ptr = (m_write_ptr + 1) % m_acl_pkts_num;
if (next_write_ptr == m_read_ptr)
{
// Many simultaneous exchanges of ACL packets tend to cause the
// 10-packet limit to be exceeded. Typically, this occurs when
// many emulated Wiimotes are requesting connections at once.
// See issue 4608 for more info.
ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue is full - current packet will be "
"dropped! (m_write_ptr(%d) was about to overlap m_read_ptr(%d))",
m_write_ptr, m_read_ptr);
return;
}
memcpy(m_pool + m_acl_pkt_size * m_write_ptr, data, size);
m_info[m_write_ptr].size = size;
m_info[m_write_ptr].conn_handle = conn_handle;
m_write_ptr = next_write_ptr;
}
void Store(const u8* data, const u16 size, const u16 conn_handle);
void WriteToEndpoint(CtrlBuffer& endpoint);
bool IsEmpty() const
{
return m_write_ptr == m_read_ptr;
}
int GetWritePos() const
{
return m_write_ptr;
}
int GetReadPos() const
{
return m_read_ptr;
return m_queue.empty();
}
// For SaveStates
void DoState(PointerWrap &p)
{
p.Do(m_write_ptr);
p.Do(m_read_ptr);
p.DoArray((u8 *)m_pool, sizeof(m_pool));
p.DoArray((u8 *)m_info, sizeof(m_info));
p.Do(m_queue);
}
} m_acl_pool;

View file

@ -139,14 +139,13 @@ void Jit64::lXXx(UGeckoInstruction inst)
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
gpr.Flush(FLUSH_ALL);
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
// if it's still 0, we can wait until the next event
TEST(32, R(EAX), R(EAX));
FixupBranch noIdle = J_CC(CC_NZ);
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionC((void *)&PowerPC::OnIdle, PowerPC::ppcState.gpr[a] + (s32)(s16)inst.SIMM_16);
// ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0

View file

@ -71,7 +71,7 @@ void JitILAsmRoutineManager::Generate()
#endif
// INT3();
const u8 *outerLoop = GetCodePtr();
const u8 *outer_loop = GetCodePtr();
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
@ -220,7 +220,7 @@ void JitILAsmRoutineManager::Generate()
MOV(32, M(&PC), R(EAX));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true);
J_CC(CC_Z, outer_loop, true);
//Landing pad for drec space
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();

View file

@ -70,8 +70,8 @@ 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 = 10;
// Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 13;
struct StateHeader
{

View file

@ -222,7 +222,7 @@ bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type,
// u64 size = header.block_size;
std::fill(in_buf, in_buf + header.block_size, 0);
if (scrubbing)
DiscScrubber::GetNextBlock(inf.GetHandle(), in_buf);
DiscScrubber::GetNextBlock(inf, in_buf);
else
inf.ReadBytes(in_buf, header.block_size);
z_stream z;

View file

@ -127,7 +127,7 @@ bool SetupScrub(const char* filename, int block_size)
return success;
}
void GetNextBlock(FILE* in, u8* buffer)
void GetNextBlock(File::IOFile& in, u8* buffer)
{
u64 CurrentOffset = m_BlockCount * m_BlockSize;
u64 i = CurrentOffset / CLUSTER_SIZE;
@ -136,12 +136,12 @@ void GetNextBlock(FILE* in, u8* buffer)
{
DEBUG_LOG(DISCIO, "Freeing 0x%016llx", CurrentOffset);
std::fill(buffer, buffer + m_BlockSize, 0xFF);
fseeko(in, m_BlockSize, SEEK_CUR);
in.Seek(m_BlockSize, SEEK_CUR);
}
else
{
DEBUG_LOG(DISCIO, "Used 0x%016llx", CurrentOffset);
fread(buffer, m_BlockSize, 1, in);
in.ReadBytes(buffer, m_BlockSize);
}
m_BlockCount++;

View file

@ -38,7 +38,7 @@ namespace DiscScrubber
{
bool SetupScrub(const char* filename, int block_size);
void GetNextBlock(FILE* in, u8* buffer);
void GetNextBlock(File::IOFile& in, u8* buffer);
void Cleanup();
} // namespace DiscScrubber

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

@ -43,6 +43,7 @@ public:
virtual std::string GetApploaderDate() const = 0;
virtual bool SupportsIntegrityCheck() const { return false; }
virtual bool CheckIntegrity() const { return false; }
virtual bool IsDiscTwo() const { return false; }
enum ECountry
{

View file

@ -137,4 +137,11 @@ u64 CVolumeGC::GetSize() const
return 0;
}
bool CVolumeGC::IsDiscTwo() const
{
bool discTwo;
Read(6,1, (u8*) &discTwo);
return discTwo;
}
} // namespace

View file

@ -39,6 +39,7 @@ public:
std::string GetApploaderDate() const;
ECountry GetCountry() const;
u64 GetSize() const;
bool IsDiscTwo() const;
private:
IBlobReader* m_pReader;

View file

@ -129,10 +129,10 @@ bool CVolumeWAD::GetWName(std::vector<std::wstring>& _rwNames) const
_rwNames.push_back(L"");
continue;
}
for (int i = 0; i < 42; ++i)
for (int j = 0; j < 42; ++j)
{
u16 t = Common::swap16(temp[i]);
if (t == 0 && i > 0)
u16 t = Common::swap16(temp[j]);
if (t == 0 && j > 0)
{
if (out_temp.at(out_temp.size()-1) != ' ')
out_temp.push_back(' ');

View file

@ -137,6 +137,7 @@
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>
@ -150,6 +151,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<PostBuildEvent>
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>
@ -166,6 +168,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>
@ -180,6 +183,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>
@ -195,6 +199,11 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<PostBuildEvent>
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
<<<<<<< HEAD
=======
xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
>>>>>>> master
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>
@ -210,6 +219,11 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<PostBuildEvent>
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls
<<<<<<< HEAD
=======
xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
>>>>>>> master
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command>
<Message>Copying Data\* to $(TargetDir)</Message>

View file

@ -483,8 +483,7 @@ void FifoPlayerDlg::OnBeginSearch(wxCommandEvent& event)
SearchResult result;
result.frame_idx = frame_idx;
int obj_idx = m_objectsList->GetSelection();
result.obj_idx = obj_idx;
result.obj_idx = m_objectsList->GetSelection();
result.cmd_idx = 0;
for (unsigned int cmd_idx = 1; cmd_idx < m_objectCmdOffsets.size(); ++cmd_idx)
{
@ -625,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++);
@ -642,8 +643,8 @@ void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event)
{
m_objectCmdOffsets.push_back(objectdata - objectdata_start);
int new_offset = objectdata - &fifo_frame.fifoData[frame.objectStarts[0]];
int cmd = *objectdata++;
switch (cmd)
int command = *objectdata++;
switch (command)
{
case GX_NOP:
newLabel = _("NOP");
@ -691,9 +692,9 @@ void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event)
case GX_LOAD_INDX_C:
case GX_LOAD_INDX_D:
objectdata += 4;
newLabel = wxString::Format(wxT("LOAD INDX %s"), (cmd == GX_LOAD_INDX_A) ? _("A") :
(cmd == GX_LOAD_INDX_B) ? _("B") :
(cmd == GX_LOAD_INDX_C) ? _("C") : _("D"));
newLabel = wxString::Format(wxT("LOAD INDX %s"), (command == GX_LOAD_INDX_A) ? _("A") :
(command == GX_LOAD_INDX_B) ? _("B") :
(command == GX_LOAD_INDX_C) ? _("C") : _("D"));
break;
case GX_CMD_CALL_DL:

View file

@ -1566,6 +1566,8 @@ void CFrame::UpdateGUI()
if (m_ToolBar)
m_ToolBar->EnableTool(IDM_PLAY, true);
GetMenuBar()->FindItem(IDM_PLAY)->Enable(true);
GetMenuBar()->FindItem(IDM_RECORD)->Enable(true);
GetMenuBar()->FindItem(IDM_PLAYRECORD)->Enable(true);
}
// Prepare to load last selected file, enable play button
else if (!SConfig::GetInstance().m_LastFilename.empty()
@ -1574,6 +1576,8 @@ void CFrame::UpdateGUI()
if (m_ToolBar)
m_ToolBar->EnableTool(IDM_PLAY, true);
GetMenuBar()->FindItem(IDM_PLAY)->Enable(true);
GetMenuBar()->FindItem(IDM_RECORD)->Enable(true);
GetMenuBar()->FindItem(IDM_PLAYRECORD)->Enable(true);
}
else
{
@ -1581,6 +1585,8 @@ void CFrame::UpdateGUI()
if (m_ToolBar)
m_ToolBar->EnableTool(IDM_PLAY, false);
GetMenuBar()->FindItem(IDM_PLAY)->Enable(false);
GetMenuBar()->FindItem(IDM_RECORD)->Enable(false);
GetMenuBar()->FindItem(IDM_PLAYRECORD)->Enable(false);
}
}
@ -1596,6 +1602,8 @@ void CFrame::UpdateGUI()
if (m_ToolBar)
m_ToolBar->EnableTool(IDM_PLAY, true);
GetMenuBar()->FindItem(IDM_PLAY)->Enable(true);
GetMenuBar()->FindItem(IDM_RECORD)->Enable(true);
GetMenuBar()->FindItem(IDM_PLAYRECORD)->Enable(true);
}
}
else if (Initialized)

View file

@ -26,6 +26,12 @@ void cInterfaceEGL::UpdateFPSDisplay(const char *text)
{
XStoreName(GLWin.dpy, GLWin.win, text);
}
void cInterfaceEGL::SwapInterval(int Interval)
{
eglSwapInterval(GLWin.egl_dpy, Interval);
}
void cInterfaceEGL::Swap()
{
eglSwapBuffers(GLWin.egl_dpy, GLWin.egl_surf);
@ -42,38 +48,30 @@ bool cInterfaceEGL::Create(void *&window_handle)
s_backbuffer_width = _twidth;
s_backbuffer_height = _theight;
const char *s;
EGLint egl_major, egl_minor;
EGLint egl_major, egl_minor;
GLWin.dpy = XOpenDisplay(NULL);
GLWin.dpy = XOpenDisplay(NULL);
if (!GLWin.dpy) {
printf("Error: couldn't open display\n");
return false;
}
if (!GLWin.dpy) {
ERROR_LOG(VIDEO, "Error: couldn't open display\n");
return false;
}
GLWin.egl_dpy = eglGetDisplay(GLWin.dpy);
if (!GLWin.egl_dpy) {
printf("Error: eglGetDisplay() failed\n");
return false;
}
GLWin.egl_dpy = eglGetDisplay(GLWin.dpy);
if (!GLWin.egl_dpy) {
ERROR_LOG(VIDEO, "Error: eglGetDisplay() failed\n");
return false;
}
if (!eglInitialize(GLWin.egl_dpy, &egl_major, &egl_minor)) {
printf("Error: eglInitialize() failed\n");
return false;
}
if (!eglInitialize(GLWin.egl_dpy, &egl_major, &egl_minor)) {
ERROR_LOG(VIDEO, "Error: eglInitialize() failed\n");
return false;
}
s = eglQueryString(GLWin.egl_dpy, EGL_VERSION);
printf("EGL_VERSION = %s\n", s);
s = eglQueryString(GLWin.egl_dpy, EGL_VENDOR);
printf("EGL_VENDOR = %s\n", s);
s = eglQueryString(GLWin.egl_dpy, EGL_EXTENSIONS);
printf("EGL_EXTENSIONS = %s\n", s);
s = eglQueryString(GLWin.egl_dpy, EGL_CLIENT_APIS);
printf("EGL_CLIENT_APIS = %s\n", s);
INFO_LOG(VIDEO, "EGL_VERSION = %s\n", eglQueryString(GLWin.egl_dpy, EGL_VERSION));
INFO_LOG(VIDEO, "EGL_VENDOR = %s\n", eglQueryString(GLWin.egl_dpy, EGL_VENDOR));
INFO_LOG(VIDEO, "EGL_EXTENSIONS = %s\n", eglQueryString(GLWin.egl_dpy, EGL_EXTENSIONS));
INFO_LOG(VIDEO, "EGL_CLIENT_APIS = %s\n", eglQueryString(GLWin.egl_dpy, EGL_CLIENT_APIS));
// attributes for a visual in RGBA format with at least
// 8 bits per color and a 24 bit depth buffer
@ -102,29 +100,29 @@ bool cInterfaceEGL::Create(void *&window_handle)
if (GLWin.parent == 0)
GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen);
XVisualInfo visTemplate;
int num_visuals;
EGLConfig config;
EGLint num_configs;
EGLint vid;
XVisualInfo visTemplate;
int num_visuals;
EGLConfig config;
EGLint num_configs;
EGLint vid;
if (!eglChooseConfig( GLWin.egl_dpy, attribs, &config, 1, &num_configs)) {
printf("Error: couldn't get an EGL visual config\n");
exit(1);
}
if (!eglChooseConfig( GLWin.egl_dpy, attribs, &config, 1, &num_configs)) {
ERROR_LOG(VIDEO, "Error: couldn't get an EGL visual config\n");
return false;
}
if (!eglGetConfigAttrib(GLWin.egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
printf("Error: eglGetConfigAttrib() failed\n");
exit(1);
}
if (!eglGetConfigAttrib(GLWin.egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
ERROR_LOG(VIDEO, "Error: eglGetConfigAttrib() failed\n");
return false;
}
/* The X window visual must match the EGL config */
visTemplate.visualid = vid;
GLWin.vi = XGetVisualInfo(GLWin.dpy, VisualIDMask, &visTemplate, &num_visuals);
if (!GLWin.vi) {
printf("Error: couldn't get X visual\n");
exit(1);
}
/* The X window visual must match the EGL config */
visTemplate.visualid = vid;
GLWin.vi = XGetVisualInfo(GLWin.dpy, VisualIDMask, &visTemplate, &num_visuals);
if (!GLWin.vi) {
ERROR_LOG(VIDEO, "Error: couldn't get X visual\n");
return false;
}
GLWin.x = _tx;
GLWin.y = _ty;
@ -138,33 +136,26 @@ bool cInterfaceEGL::Create(void *&window_handle)
eglBindAPI(EGL_OPENGL_API);
#endif
GLWin.egl_ctx = eglCreateContext(GLWin.egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
if (!GLWin.egl_ctx) {
printf("Error: eglCreateContext failed\n");
exit(1);
}
if (!GLWin.egl_ctx) {
ERROR_LOG(VIDEO, "Error: eglCreateContext failed\n");
return false;
}
GLWin.egl_surf = eglCreateWindowSurface(GLWin.egl_dpy, config, GLWin.win, NULL);
if (!GLWin.egl_surf) {
printf("Error: eglCreateWindowSurface failed\n");
exit(1);
}
GLWin.egl_surf = eglCreateWindowSurface(GLWin.egl_dpy, config, GLWin.win, NULL);
if (!GLWin.egl_surf) {
ERROR_LOG(VIDEO, "Error: eglCreateWindowSurface failed\n");
return false;
}
if (!eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) {
printf("Error: eglMakeCurrent() failed\n");
return false;
}
if (!eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) {
ERROR_LOG(VIDEO, "Error: eglMakeCurrent() failed\n");
return false;
}
printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
/* Set initial projection/viewing transformation.
* We can't be sure we'll get a ConfigureNotify event when the window
* first appears.
*/
glViewport(0, 0, (GLint) _twidth, (GLint) _theight);
INFO_LOG(VIDEO, "GL_VENDOR: %s\n", glGetString(GL_VENDOR));
INFO_LOG(VIDEO, "GL_RENDERER: %s\n", glGetString(GL_RENDERER));
INFO_LOG(VIDEO, "GL_VERSION: %s\n", glGetString(GL_VERSION));
INFO_LOG(VIDEO, "GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
window_handle = (void *)GLWin.win;
return true;
}

View file

@ -34,6 +34,7 @@ private:
cX11Window XWindow;
public:
friend class cX11Window;
void SwapInterval(int Interval);
void Swap();
void UpdateFPSDisplay(const char *Text);
bool Create(void *&window_handle);

View file

@ -27,6 +27,15 @@ void cInterfaceGLX::UpdateFPSDisplay(const char *text)
{
XStoreName(GLWin.dpy, GLWin.win, text);
}
void cInterfaceGLX::SwapInterval(int Interval)
{
if (glXSwapIntervalSGI)
glXSwapIntervalSGI(Interval);
else
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
}
void cInterfaceGLX::Swap()
{
glXSwapBuffers(GLWin.dpy, GLWin.win);

View file

@ -31,6 +31,7 @@ private:
cX11Window XWindow;
public:
friend class cX11Window;
void SwapInterval(int Interval);
void Swap();
void UpdateFPSDisplay(const char *Text);
bool Create(void *&window_handle);

View file

@ -29,6 +29,7 @@ public:
virtual bool MakeCurrent() = 0;
virtual void Shutdown() = 0;
virtual void SwapInterval(int Interval) { }
virtual u32 GetBackBufferWidth() { return s_backbuffer_width; }
virtual u32 GetBackBufferHeight() { return s_backbuffer_height; }
virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; }

View file

@ -27,6 +27,13 @@
static HDC hDC = NULL; // Private GDI Device Context
static HGLRC hRC = NULL; // Permanent Rendering Context
void cInterfaceWGL::SwapInterval(int Interval)
{
if (WGLEW_EXT_swap_control)
wglSwapIntervalEXT(Interval);
else
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
}
void cInterfaceWGL::Swap()
{
SwapBuffers(hDC);

View file

@ -28,6 +28,7 @@
class cInterfaceWGL : public cInterfaceBase
{
public:
void SwapInterval(int Interval);
void Swap();
void UpdateFPSDisplay(const char *Text);
bool Create(void *&window_handle);

View file

@ -57,6 +57,8 @@ size_t CGameListCtrl::m_numberItem = 0;
std::string CGameListCtrl::m_currentFilename;
bool sorted = false;
extern CFrame* main_frame;
static int CompareGameListItems(const GameListItem* iso1, const GameListItem* iso2,
long sortData = CGameListCtrl::COLUMN_TITLE)
{
@ -94,6 +96,13 @@ static int CompareGameListItems(const GameListItem* iso1, const GameListItem* is
switch(sortData)
{
case CGameListCtrl::COLUMN_TITLE:
if (!strcasecmp(iso1->GetName(indexOne).c_str(),iso2->GetName(indexOther).c_str()))
{
if (iso1->IsDiscTwo())
return 1 * t;
else if (iso2->IsDiscTwo())
return -1 * t;
}
return strcasecmp(iso1->GetName(indexOne).c_str(),
iso2->GetName(indexOther).c_str()) * t;
case CGameListCtrl::COLUMN_NOTES:
@ -366,7 +375,8 @@ void CGameListCtrl::Update()
SetItemFont(index, *wxITALIC_FONT);
SetColumnWidth(0, wxLIST_AUTOSIZE);
}
if (GetSelectedISO() == NULL)
main_frame->UpdateGUI();
Show();
AutomaticColumnWidth();
@ -968,7 +978,7 @@ const GameListItem * CGameListCtrl::GetSelectedISO()
{
long item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
if (item == wxNOT_FOUND)
return new GameListItem(""); // TODO: wtf is this
return NULL;
else
{
// Here is a little workaround for multiselections:

View file

@ -36,7 +36,7 @@
#include "ChunkFile.h"
#include "../resources/no_banner.cpp"
#define CACHE_REVISION 0x10E
#define CACHE_REVISION 0x10F
#define DVD_BANNER_WIDTH 96
#define DVD_BANNER_HEIGHT 32
@ -91,6 +91,7 @@ GameListItem::GameListItem(const std::string& _rFileName)
m_UniqueID = pVolume->GetUniqueID();
m_BlobCompressed = DiscIO::IsCompressedBlob(_rFileName.c_str());
m_IsDiscTwo = pVolume->IsDiscTwo();
// check if we can get some infos from the banner file too
DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume);
@ -235,6 +236,7 @@ void GameListItem::DoState(PointerWrap &p)
p.Do(m_BlobCompressed);
p.Do(m_pImage);
p.Do(m_Platform);
p.Do(m_IsDiscTwo);
}
std::string GameListItem::CreateCacheFilename()

View file

@ -48,6 +48,7 @@ public:
bool IsCompressed() const {return m_BlobCompressed;}
u64 GetFileSize() const {return m_FileSize;}
u64 GetVolumeSize() const {return m_VolumeSize;}
bool IsDiscTwo() const {return m_IsDiscTwo;}
#if defined(HAVE_WX) && HAVE_WX
const wxImage& GetImage() const {return m_Image;}
#endif
@ -87,6 +88,7 @@ private:
bool m_BlobCompressed;
std::vector<u8> m_pImage;
u32 m_ImageSize;
bool m_IsDiscTwo;
bool LoadFromCache();
void SaveToCache();

View file

@ -328,8 +328,6 @@ void CISOProperties::CreateGUIControls(bool IsWad)
// Wii Console
EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DisableWiimoteSpeaker = new wxCheckBox(m_GameConfig, ID_DISABLEWIIMOTESPEAKER, _("Alternate Wiimote Timing"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DisableWiimoteSpeaker->SetToolTip(_("Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes."));
// Video
UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
@ -377,10 +375,8 @@ void CISOProperties::CreateGUIControls(bool IsWad)
{
sbWiiOverrides->ShowItems(false);
EnableWideScreen->Hide();
DisableWiimoteSpeaker->Hide();
}
sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5);
sbWiiOverrides->Add(DisableWiimoteSpeaker, 0, wxLEFT, 5);
wxStaticBoxSizer * const sbVideoOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video"));
@ -966,11 +962,6 @@ void CISOProperties::LoadGameConfig()
else
EnableWideScreen->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Wii", "DisableWiimoteSpeaker", &bTemp))
DisableWiimoteSpeaker->Set3StateValue((wxCheckBoxState)bTemp);
else
DisableWiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "UseBBox", &bTemp))
UseBBox->Set3StateValue((wxCheckBoxState)bTemp);
else
@ -999,7 +990,6 @@ void CISOProperties::LoadGameConfig()
if (!sTemp.empty())
{
EmuIssues->SetValue(wxString(sTemp.c_str(), *wxConvCurrent));
bRefreshList = true;
}
EmuIssues->Enable(EmuState->GetSelection() != 0);
@ -1060,11 +1050,6 @@ bool CISOProperties::SaveGameConfig()
else
GameIni.Set("Wii", "Widescreen", EnableWideScreen->Get3StateValue());
if (DisableWiimoteSpeaker->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "DisableWiimoteSpeaker");
else
GameIni.Set("Wii", "DisableWiimoteSpeaker", DisableWiimoteSpeaker->Get3StateValue());
if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "UseBBox");
else
@ -1085,6 +1070,11 @@ bool CISOProperties::SaveGameConfig()
GameIni.Set("Video", "PH_ZFar", PHack_Data.PHZFar);
GameIni.Set("EmuState", "EmulationStateId", EmuState->GetSelection());
std::string sTemp;
GameIni.Get("EmuState","EmulationIssues", &sTemp);
if (EmuIssues->GetValue() != sTemp)
bRefreshList = true;
GameIni.Set("EmuState", "EmulationIssues", (const char*)EmuIssues->GetValue().mb_str(*wxConvCurrent));
PatchList_Save();

View file

@ -72,7 +72,7 @@ private:
wxCheckBox *CPUThread, *SkipIdle, *MMU, *DCBZOFF, *TLBHack;
wxCheckBox *VBeam, *FastDiscSpeed, *BlockMerging, *DSPHLE;
// Wii
wxCheckBox *EnableWideScreen, *DisableWiimoteSpeaker;
wxCheckBox *EnableWideScreen;
// Video
wxCheckBox *UseZTPSpeedupHack, *PHackEnable, *UseBBox;
wxButton *PHSettings;
@ -139,7 +139,6 @@ private:
ID_PHSETTINGS,
ID_ENABLEPROGRESSIVESCAN,
ID_ENABLEWIDESCREEN,
ID_DISABLEWIIMOTESPEAKER,
ID_EDITCONFIG,
ID_EMUSTATE,
ID_EMU_ISSUES,

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

@ -1099,8 +1099,8 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
y = y/2;
wxMemoryDC memDC;
wxBitmap bitmap(127, 127);
memDC.SelectObject(bitmap);
wxBitmap stick_bitmap(127, 127);
memDC.SelectObject(stick_bitmap);
memDC.SetBackground(*wxLIGHT_GREY_BRUSH);
memDC.Clear();
memDC.SetBrush(*wxWHITE_BRUSH);
@ -1116,5 +1116,5 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
memDC.SetBrush(*wxBLUE_BRUSH);
memDC.DrawCircle(x,y,5);
memDC.SelectObject(wxNullBitmap);
return bitmap;
return stick_bitmap;
}

View file

@ -124,12 +124,12 @@ void EWMH_Fullscreen(Display *dpy, int action)
#if defined(HAVE_WX) && HAVE_WX
Window XWindowFromHandle(void *Handle)
{
return GDK_WINDOW_XID(GTK_WIDGET(Handle)->window);
return GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(Handle)));
}
Display *XDisplayFromHandle(void *Handle)
{
return GDK_WINDOW_XDISPLAY(GTK_WIDGET(Handle)->window);
return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(GTK_WIDGET(Handle)));
}
#endif

View file

@ -1,279 +1,28 @@
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,
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, 0x04, 0x03,
0x00, 0x00, 0x00, 0x1f, 0xee, 0x60, 0x67, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48,
0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a,
0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xdd, 0x02,
0x09, 0x16, 0x39, 0x17, 0xf0, 0x40, 0x6e, 0x04, 0x00, 0x00, 0x00, 0x15, 0x50,
0x4c, 0x54, 0x45, 0x66, 0x66, 0x66, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6d,
0x6d, 0x6d, 0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x80, 0x80, 0x80, 0xd1, 0x7d,
0x40, 0x35, 0x00, 0x00, 0x00, 0xc6, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x8d,
0xd4, 0x31, 0x0e, 0xc3, 0x20, 0x10, 0x44, 0xd1, 0x51, 0x64, 0xfa, 0x1c, 0x25,
0x47, 0x48, 0x45, 0xed, 0xca, 0x07, 0xb0, 0x80, 0xfb, 0x1f, 0x21, 0x05, 0x60,
0xd6, 0x30, 0xe3, 0xac, 0xbb, 0x95, 0xf8, 0x7a, 0xb2, 0x01, 0xa3, 0x98, 0x27,
0x01, 0x00, 0x10, 0xfa, 0x9c, 0xeb, 0xbc, 0xd9, 0x35, 0xb0, 0x43, 0xf9, 0xd6,
0x15, 0x47, 0x1b, 0xf7, 0x3a, 0x46, 0x1d, 0xdc, 0x09, 0x06, 0x4c, 0xc1, 0x9d,
0x60, 0xc0, 0x1c, 0x58, 0x82, 0x02, 0x73, 0x60, 0x09, 0x0a, 0x2c, 0xc1, 0x20,
0x38, 0xb0, 0x04, 0x83, 0xe0, 0xc0, 0x1a, 0x74, 0x42, 0x00, 0x6b, 0xd0, 0x89,
0x0f, 0x07, 0x48, 0xd0, 0x08, 0x01, 0x90, 0xa0, 0x13, 0x1c, 0x60, 0x41, 0x7a,
0x02, 0x58, 0x60, 0x88, 0xe8, 0x0b, 0xd2, 0x03, 0x40, 0x83, 0x8b, 0x88, 0xde,
0xe0, 0xac, 0xeb, 0x5f, 0xc5, 0x1b, 0xb4, 0x4d, 0xbe, 0xee, 0xc5, 0xbf, 0x20,
0xf7, 0x77, 0x08, 0xce, 0x60, 0xbf, 0xbe, 0xd2, 0xe1, 0x0a, 0xf2, 0xd8, 0x87,
0xe0, 0x0a, 0x76, 0xb3, 0xd3, 0x87, 0x23, 0xc8, 0xf6, 0x2c, 0x05, 0x47, 0xd0,
0x80, 0xb7, 0x20, 0x20, 0x80, 0x2d, 0x09, 0x02, 0x02, 0x88, 0xf3, 0x3f, 0x4a,
0x05, 0xe3, 0xa2, 0x09, 0x02, 0x0a, 0x28, 0x82, 0x80, 0x02, 0x14, 0x01, 0x09,
0x08, 0x02, 0x12, 0x10, 0x04, 0x34, 0xc0, 0x89, 0x1f, 0xe2, 0x9a, 0xca, 0x1c,
0x5f, 0x12, 0x62, 0x57, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
0x42, 0x60, 0x82
};

View file

@ -121,7 +121,9 @@ Joystick::Axis::Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction d
// Need to parse the element a bit first
std::string description("unk");
switch (IOHIDElementGetUsage(m_element)) {
int const usage = IOHIDElementGetUsage(m_element);
switch (usage)
{
case kHIDUsage_GD_X:
description = "X";
break;
@ -146,6 +148,13 @@ Joystick::Axis::Axis(IOHIDElementRef element, IOHIDDeviceRef device, direction d
case kHIDUsage_Csmr_ACPan:
description = "Pan";
break;
default:
{
std::ostringstream s;
s << usage;
description = s.str();
break;
}
}
m_name = std::string("Axis ") + description;

View file

@ -458,6 +458,7 @@ void BPWritten(const BPCmd& bp)
case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel
g_renderer->SetBlendMode(true);
OnPixelFormatChange();
if(bp.changes & 3)
SetBlendMode(); // dual source could be activated by changing to PIXELFMT_RGBA6_Z24
@ -523,9 +524,8 @@ void BPWritten(const BPCmd& bp)
for (u32 i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
{
// FIXME: Duplicate conditions.
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE)
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
break;
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);

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;
@ -218,6 +217,9 @@ void TextureCache::ClearRenderTargets()
bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels)
{
if (levels == 1)
return false;
// Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black
char texBasePathTemp[MAX_PATH];
char texPathTemp[MAX_PATH];
@ -298,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 UseNativeMips, 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 const 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;
@ -314,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;
@ -329,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);
@ -366,15 +385,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)
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.
@ -382,7 +403,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
@ -395,9 +417,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)
{
@ -428,26 +452,26 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
}
}
// TODO: Cleanup. Plus, we still autogenerate mipmaps in certain cases (we shouldn't do that)
bool isPow2;
unsigned int texLevels;
isPow2 = !((width & (width - 1)) || (height & (height - 1)));
texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2;
texLevels = maxlevel ? std::min(texLevels, maxlevel + 1) : texLevels;
using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
UseNativeMips = UseNativeMips && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
texLevels = (UseNativeMips || using_custom_lods) ? texLevels : !isPow2;
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;
// 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: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
// 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);
@ -460,83 +484,63 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
else entry->type = TCET_NORMAL;
// load texture
entry->Load(stage, width, height, expandedWidth, 0, (texLevels == 0));
entry->Load(stage, width, height, expandedWidth, 0);
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 && UseNativeMips)
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(stage, 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(stage, currentWidth, currentHeight, expandedWidth, level, false);
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(stage, currentWidth, currentHeight, currentWidth, level, false);
mipWidth >>= 1;
mipHeight >>= 1;
++level;
LoadCustomTexture(tex_hash, texformat, level, mip_width, mip_height);
entry->Load(stage, 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

@ -60,26 +60,26 @@ public:
int frameCount;
void SetGeneralParameters(u32 addr, u32 size, u32 format, unsigned int num_mipmaps)
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps)
{
this->addr = addr;
this->size_in_bytes = size;
this->format = format;
this->num_mipmaps = num_mipmaps;
addr = _addr;
size_in_bytes = _size;
format = _format;
num_mipmaps = _num_mipmaps;
}
void SetDimensions(unsigned int native_width, unsigned int native_height, unsigned int virtual_width, unsigned int virtual_height)
void SetDimensions(unsigned int _native_width, unsigned int _native_height, unsigned int _virtual_width, unsigned int _virtual_height)
{
this->native_width = native_width;
this->native_height = native_height;
this->virtual_width = virtual_width;
this->virtual_height = virtual_height;
native_width = _native_width;
native_height = _native_height;
virtual_width = _virtual_width;
virtual_height = _virtual_height;
}
void SetHashes(u64 hash/*, u32 pal_hash*/)
void SetHashes(u64 _hash/*, u32 _pal_hash*/)
{
this->hash = hash;
//this->pal_hash = pal_hash;
hash = _hash;
//pal_hash = _pal_hash;
}
@ -89,7 +89,7 @@ public:
virtual bool Save(const char filename[], unsigned int level) = 0;
virtual void Load(unsigned int stage, unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
unsigned int expanded_width, unsigned int level) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
@ -116,7 +116,7 @@ public:
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem);
int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);

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
{