Merge branch 'master' into wii-network
This commit is contained in:
commit
6eb2cb2666
|
@ -554,6 +554,7 @@ option(UNITTESTS "Build unitests" OFF)
|
|||
########################################
|
||||
# Start compiling our code
|
||||
#
|
||||
add_definitions(-std=c++0x)
|
||||
add_subdirectory(Source)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# G3LE8P - Super Monkey Ball Adventures (TM)
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# GP8EAF - Pac-Man World 3
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,9 @@
|
|||
# JAEE01 - Donkey Kong Country
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# JBKP01 -
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# R8XE52 - Jurassic: The Hunted
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# R9IE01 - PIKMIN1 for Wii
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# RBME5G - Bust-a-Move BASH!
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,16 @@
|
|||
# RGHE52 - Sample Game Name
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
FastDiscSpeed = 0
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# RLBEWR - LEGO Batman
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# RS8J8N - SHANGHAI
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# SDFE4Q - Disney Sing It: Family Hits
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# SS3EWR - Elmo's A to Zoo Adventure
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 5
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# STEETR - Tetris Party Deluxe
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# WBME01 - My Pokémon Ranch
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -0,0 +1,15 @@
|
|||
# WPPJJF - JM‰OÔóÝóWii
|
||||
[Core] Values set here will override the main dolphin settings.
|
||||
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationStateId = 0
|
||||
EmulationIssues =
|
||||
[OnFrame] Add memory patches to be applied every frame here.
|
||||
[ActionReplay] Add action replay cheats here.
|
||||
[Video]
|
||||
ProjectionHack = 0
|
||||
PH_SZNear = 0
|
||||
PH_SZFar = 0
|
||||
PH_ExtraParam = 0
|
||||
PH_ZNear =
|
||||
PH_ZFar =
|
||||
[Gecko]
|
|
@ -4588,7 +4588,7 @@ msgid ""
|
|||
"The safer you adjust this, the less likely the emulator will be missing any "
|
||||
"texture updates from RAM.\n"
|
||||
"\n"
|
||||
"If unsure, use the second-fastest value from the right."
|
||||
"If unsure, use the rightmost value."
|
||||
msgstr ""
|
||||
|
||||
#: Source/Core/DolphinWX/Src/MemcardManager.cpp:447
|
||||
|
|
|
@ -189,7 +189,7 @@ unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
|||
#ifdef __GNUC__
|
||||
(frameSize + 15) & -16;
|
||||
#else
|
||||
frameSize;
|
||||
(frameSize + 3) & -4;
|
||||
#endif
|
||||
return alignedSize;
|
||||
}
|
||||
|
@ -200,16 +200,15 @@ void XEmitter::ABI_AlignStack(unsigned int frameSize) {
|
|||
// Linux requires the stack to be 16-byte aligned before calls that put SSE
|
||||
// vectors on the stack, but since we do not keep track of which calls do that,
|
||||
// it is effectively every call as well.
|
||||
// Windows binaries compiled with MSVC do not have such a restriction, but I
|
||||
// Windows binaries compiled with MSVC do not have such a restriction*, but I
|
||||
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
|
||||
// It would be nice if someone could verify this.
|
||||
#ifdef __GNUC__
|
||||
// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
|
||||
unsigned int fillSize =
|
||||
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
|
||||
if (fillSize != 0) {
|
||||
SUB(32, R(ESP), Imm8(fillSize));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int frameSize) {
|
||||
|
|
|
@ -139,14 +139,18 @@ private:
|
|||
// wxWidgets does not have a true dummy macro for this.
|
||||
#define _trans(a) a
|
||||
|
||||
#if defined __APPLE__ && defined __i386__
|
||||
#define _M_SSE 0x300
|
||||
#elif defined __APPLE__ && defined __x86_64__
|
||||
#define _M_SSE 0x301
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
|
||||
#define _M_SSE 0x301
|
||||
#if defined __GNUC__
|
||||
# if defined __SSE4_2__
|
||||
# define _M_SSE 0x402
|
||||
# elif defined __SSE4_1__
|
||||
# define _M_SSE 0x401
|
||||
# elif defined __SSSE3__
|
||||
# define _M_SSE 0x301
|
||||
# elif defined __SSE3__
|
||||
# define _M_SSE 0x300
|
||||
# endif
|
||||
#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
|
||||
#define _M_SSE 0x402
|
||||
# define _M_SSE 0x402
|
||||
#endif
|
||||
|
||||
// Host communication.
|
||||
|
|
|
@ -167,7 +167,7 @@ u64 GetMurmurHash3(const u8 *src, int len, u32 samples)
|
|||
const u8 * data = (const u8*)src;
|
||||
const int nblocks = len / 16;
|
||||
u32 Step = (len / 8);
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
|
||||
|
@ -245,7 +245,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
|
|||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
|
@ -275,7 +275,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
|
|||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
|
@ -318,7 +318,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
|
|||
u32 Step = (len/4);
|
||||
const u32 *data = (const u32 *)src;
|
||||
const u32 *end = data + Step;
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
|
@ -390,7 +390,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
|
|||
u32 out[2];
|
||||
const int nblocks = len / 8;
|
||||
u32 Step = (len / 4);
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
|
||||
|
@ -464,7 +464,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
|
|||
u32 Step = (len / 8);
|
||||
const u64 *data = (const u64 *)src;
|
||||
const u64 *end = data + Step;
|
||||
if(samples == 0) samples = Step;
|
||||
if(samples == 0) samples = max(Step, 1u);
|
||||
Step = Step / samples;
|
||||
if(Step < 1) Step = 1;
|
||||
while(data < end)
|
||||
|
|
|
@ -459,7 +459,11 @@ bool IniFile::Save(const char* filename)
|
|||
return false;
|
||||
}
|
||||
|
||||
for (std::vector<Section>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
// Currently testing if dolphin community can handle the requirements of C++11 compilation
|
||||
// If you get a compiler error on this line, your compiler is probably old.
|
||||
// Update to g++ 4.4 or a recent version of clang (XCode 4.2 on OS X).
|
||||
// If you don't want to update, complain in a google code issue, the dolphin forums or #dolphin-emu.
|
||||
for (auto iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
{
|
||||
const Section& section = *iter;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
// Increment this every time you change shader generation code.
|
||||
enum
|
||||
{
|
||||
LINEAR_DISKCACHE_VER = 6969
|
||||
LINEAR_DISKCACHE_VER = 6972
|
||||
};
|
||||
|
||||
// On disk format:
|
||||
|
|
|
@ -85,12 +85,17 @@ LogManager::LogManager()
|
|||
|
||||
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
|
||||
m_consoleLog = new ConsoleListener();
|
||||
m_debuggerLog = new DebuggerLogListener();
|
||||
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
m_Log[i]->SetEnable(true);
|
||||
m_Log[i]->AddListener(m_fileLog);
|
||||
m_Log[i]->AddListener(m_consoleLog);
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent())
|
||||
m_Log[i]->AddListener(m_debuggerLog);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +105,7 @@ LogManager::~LogManager()
|
|||
{
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
|
||||
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
|
||||
}
|
||||
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
|
@ -187,3 +193,10 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
|||
std::lock_guard<std::mutex> lk(m_log_lock);
|
||||
m_logfile << msg << std::flush;
|
||||
}
|
||||
|
||||
void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
|
||||
{
|
||||
#if _MSC_VER
|
||||
::OutputDebugStringA(msg);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -58,6 +58,12 @@ private:
|
|||
bool m_enable;
|
||||
};
|
||||
|
||||
class DebuggerLogListener : public LogListener
|
||||
{
|
||||
public:
|
||||
void Log(LogTypes::LOG_LEVELS, const char *msg);
|
||||
};
|
||||
|
||||
class LogContainer
|
||||
{
|
||||
public:
|
||||
|
@ -97,6 +103,7 @@ private:
|
|||
LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
|
||||
FileLogListener *m_fileLog;
|
||||
ConsoleListener *m_consoleLog;
|
||||
DebuggerLogListener *m_debuggerLog;
|
||||
static LogManager *m_logManager; // Singleton. Ugh.
|
||||
|
||||
LogManager();
|
||||
|
@ -153,6 +160,11 @@ public:
|
|||
return m_consoleLog;
|
||||
}
|
||||
|
||||
DebuggerLogListener *GetDebuggerListener() const
|
||||
{
|
||||
return m_debuggerLog;
|
||||
}
|
||||
|
||||
static LogManager* GetInstance()
|
||||
{
|
||||
return m_logManager;
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
|
||||
// GCC 4.4 provides <thread>
|
||||
#ifndef _GLIBCXX_USE_SCHED_YIELD
|
||||
#define _GLIBCXX_USE_SCHED_YIELD
|
||||
#endif
|
||||
#include <thread>
|
||||
#else
|
||||
|
||||
|
|
|
@ -66,10 +66,9 @@ struct SSysConfEntry
|
|||
}
|
||||
bool SetArrayData(u8* buffer, u16 bufferSize)
|
||||
{
|
||||
|
||||
if (buffer && bufferSize <= dataLength)
|
||||
if (buffer)
|
||||
{
|
||||
memcpy(data, buffer, bufferSize);
|
||||
memcpy(data, buffer, min<u16>(bufferSize, dataLength));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -834,6 +834,102 @@ void XEmitter::SHL(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, sh
|
|||
void XEmitter::SHR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 5);}
|
||||
void XEmitter::SAR(int bits, OpArg dest, OpArg shift) {WriteShift(bits, dest, shift, 7);}
|
||||
|
||||
// index can be either imm8 or register, don't use memory destination because it's slow
|
||||
void XEmitter::WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext)
|
||||
{
|
||||
if (dest.IsImm())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "WriteBitTest - can't test imms");
|
||||
}
|
||||
if ((index.IsImm() && index.GetImmBits() != 8))
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "WriteBitTest - illegal argument");
|
||||
}
|
||||
if (bits == 16) Write8(0x66);
|
||||
if (index.IsImm())
|
||||
{
|
||||
dest.WriteRex(this, bits, bits);
|
||||
Write8(0x0F); Write8(0xBA);
|
||||
dest.WriteRest(this, 1, (X64Reg)ext);
|
||||
Write8((u8)index.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
X64Reg operand = index.GetSimpleReg();
|
||||
dest.WriteRex(this, bits, bits, operand);
|
||||
Write8(0x0F); Write8(0x83 + 8*ext);
|
||||
dest.WriteRest(this, 1, operand);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::BT(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 4);}
|
||||
void XEmitter::BTS(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 5);}
|
||||
void XEmitter::BTR(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 6);}
|
||||
void XEmitter::BTC(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, index, 7);}
|
||||
|
||||
//shift can be either imm8 or cl
|
||||
void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift)
|
||||
{
|
||||
bool writeImm = false;
|
||||
if (dest.IsImm())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination");
|
||||
}
|
||||
if (!src.IsSimpleReg())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHRD - must use simple register as source");
|
||||
}
|
||||
if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHRD - illegal shift");
|
||||
}
|
||||
if (bits == 16) Write8(0x66);
|
||||
X64Reg operand = src.GetSimpleReg();
|
||||
dest.WriteRex(this, bits, bits, operand);
|
||||
if (shift.GetImmBits() == 8)
|
||||
{
|
||||
Write8(0x0F); Write8(0xAC);
|
||||
dest.WriteRest(this, 1, operand);
|
||||
Write8((u8)shift.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write8(0x0F); Write8(0xAD);
|
||||
dest.WriteRest(this, 0, operand);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift)
|
||||
{
|
||||
bool writeImm = false;
|
||||
if (dest.IsImm())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination");
|
||||
}
|
||||
if (!src.IsSimpleReg())
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHLD - must use simple register as source");
|
||||
}
|
||||
if ((shift.IsSimpleReg() && shift.GetSimpleReg() != ECX) || (shift.IsImm() && shift.GetImmBits() != 8))
|
||||
{
|
||||
_assert_msg_(DYNA_REC, 0, "SHLD - illegal shift");
|
||||
}
|
||||
if (bits == 16) Write8(0x66);
|
||||
X64Reg operand = src.GetSimpleReg();
|
||||
dest.WriteRex(this, bits, bits, operand);
|
||||
if (shift.GetImmBits() == 8)
|
||||
{
|
||||
Write8(0x0F); Write8(0xA4);
|
||||
dest.WriteRest(this, 1, operand);
|
||||
Write8((u8)shift.offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Write8(0x0F); Write8(0xA5);
|
||||
dest.WriteRest(this, 0, operand);
|
||||
}
|
||||
}
|
||||
|
||||
void OpArg::WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg _operandReg, int bits)
|
||||
{
|
||||
if (bits == 16)
|
||||
|
|
|
@ -249,6 +249,7 @@ private:
|
|||
void WriteMulDivType(int bits, OpArg src, int ext);
|
||||
void WriteBitSearchType(int bits, X64Reg dest, OpArg src, u8 byte2);
|
||||
void WriteShift(int bits, OpArg dest, OpArg &shift, int ext);
|
||||
void WriteBitTest(int bits, OpArg &dest, OpArg &index, int ext);
|
||||
void WriteMXCSR(OpArg arg, int ext);
|
||||
void WriteSSEOp(int size, u8 sseOp, bool packed, X64Reg regOp, OpArg arg, int extrabytes = 0);
|
||||
void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg &a1, const OpArg &a2);
|
||||
|
@ -374,6 +375,16 @@ public:
|
|||
void SHR(int bits, OpArg dest, OpArg shift);
|
||||
void SAR(int bits, OpArg dest, OpArg shift);
|
||||
|
||||
// Bit Test
|
||||
void BT(int bits, OpArg dest, OpArg index);
|
||||
void BTS(int bits, OpArg dest, OpArg index);
|
||||
void BTR(int bits, OpArg dest, OpArg index);
|
||||
void BTC(int bits, OpArg dest, OpArg index);
|
||||
|
||||
// Double-Precision Shift
|
||||
void SHRD(int bits, OpArg dest, OpArg src, OpArg shift);
|
||||
void SHLD(int bits, OpArg dest, OpArg src, OpArg shift);
|
||||
|
||||
// Extend EAX into EDX in various ways
|
||||
void CWD(int bits = 16);
|
||||
inline void CDQ() {CWD(32);}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
====================================================================*/
|
||||
|
||||
|
|
|
@ -85,14 +85,14 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
|
|||
|
||||
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
|
||||
{
|
||||
tlutAddr = (bpMem.tlutXferDest & 0x3FF) << 9;
|
||||
tlutXferCount = (bpMem.tlutXferDest & 0x1FFC00) >> 5;
|
||||
tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
|
||||
tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
|
||||
|
||||
// TODO - figure out a cleaner way.
|
||||
if (Core::g_CoreStartupParameter.bWii)
|
||||
memAddr = bpmem.tlutXferSrc << 5;
|
||||
memAddr = bpmem.tmem_config.tlut_src << 5;
|
||||
else
|
||||
memAddr = (bpmem.tlutXferSrc & 0xFFFFF) << 5;
|
||||
memAddr = (bpmem.tmem_config.tlut_src & 0xFFFFF) << 5;
|
||||
}
|
||||
|
||||
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
|
||||
|
|
|
@ -49,6 +49,9 @@ DSPLLE::DSPLLE() {
|
|||
m_cycle_count = 0;
|
||||
}
|
||||
|
||||
Common::Event dspEvent;
|
||||
Common::Event ppcEvent;
|
||||
|
||||
void DSPLLE::DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(g_dsp.r);
|
||||
|
@ -96,7 +99,10 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle)
|
|||
Common::AtomicStore(dsp_lle->m_cycle_count, 0);
|
||||
}
|
||||
else
|
||||
Common::YieldCPU();
|
||||
{
|
||||
ppcEvent.Set();
|
||||
dspEvent.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +144,8 @@ void DSPLLE::DSP_StopSoundStream()
|
|||
m_bIsRunning = false;
|
||||
if (m_bDSPThread)
|
||||
{
|
||||
ppcEvent.Set();
|
||||
dspEvent.Set();
|
||||
m_hDSPThread.join();
|
||||
}
|
||||
}
|
||||
|
@ -274,9 +282,10 @@ void DSPLLE::DSP_Update(int cycles)
|
|||
else
|
||||
{
|
||||
// Wait for dsp thread to complete its cycle. Note: this logic should be thought through.
|
||||
while (m_cycle_count != 0)
|
||||
;
|
||||
ppcEvent.Wait();
|
||||
Common::AtomicStore(m_cycle_count, dsp_cycles);
|
||||
dspEvent.Set();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1126,7 +1126,7 @@ bool GCMemcard::Format(u8 * card_data, bool sjis, u16 SizeMb)
|
|||
gcp.bat_backup = (BlockAlloc *)(card_data + BLOCK_SIZE*4);
|
||||
|
||||
*(u16*)gcp.hdr->SizeMb = BE16(SizeMb);
|
||||
*(u16*)gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
|
||||
gcp.hdr->Encoding = BE16(sjis ? 1 : 0);
|
||||
|
||||
FormatInternal(gcp);
|
||||
return true;
|
||||
|
@ -1148,7 +1148,7 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb)
|
|||
gcp.bat_backup = &bat_backup;
|
||||
|
||||
*(u16*)hdr.SizeMb = BE16(SizeMb);
|
||||
*(u16*)hdr.Encoding = BE16(sjis ? 1 : 0);
|
||||
hdr.Encoding = BE16(sjis ? 1 : 0);
|
||||
FormatInternal(gcp);
|
||||
|
||||
m_sizeMb = SizeMb;
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
// end Serial in libogc
|
||||
u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B
|
||||
u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits
|
||||
u8 Encoding[2]; //0x0024 2 encoding (ASCII or japanese)
|
||||
u16 Encoding; //0x0024 2 encoding (ASCII or japanese)
|
||||
u8 Unused1[468]; //0x0026 468 unused (0xff)
|
||||
u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused)
|
||||
u16 Checksum; //0x01fc 2 Additive Checksum
|
||||
|
|
|
@ -129,7 +129,7 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
|
|||
[bti setInquiryLength: 5];
|
||||
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
|
||||
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
|
||||
minorDeviceClass: kBluetoothDeviceClassMinorPeripheral2Joystick
|
||||
minorDeviceClass: kBluetoothDeviceClassMinorAny
|
||||
];
|
||||
[bti setUpdateNewDeviceNames: NO];
|
||||
|
||||
|
@ -177,6 +177,10 @@ bool Wiimote::Connect()
|
|||
if (IsConnected())
|
||||
return false;
|
||||
|
||||
if ([btd remoteNameRequest:nil] == kIOReturnSuccess)
|
||||
m_motion_plus_inside =
|
||||
static_cast<bool>([[btd getName] hasSuffix:@"-TR"]);
|
||||
|
||||
[btd openL2CAPChannelSync: &cchan
|
||||
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
|
||||
[btd openL2CAPChannelSync: &ichan
|
||||
|
@ -244,7 +248,7 @@ int Wiimote::IOWrite(unsigned char *buf, int len)
|
|||
if (!IsConnected())
|
||||
return 0;
|
||||
|
||||
ret = [cchan writeAsync: buf length: len refcon: nil];
|
||||
ret = [ichan writeAsync: buf length: len refcon: nil];
|
||||
|
||||
if (ret == kIOReturnSuccess)
|
||||
return len;
|
||||
|
|
|
@ -50,6 +50,7 @@ Wiimote::Wiimote(const unsigned int _index)
|
|||
#endif
|
||||
, leds(0), m_last_data_report(Report((u8 *)NULL, 0))
|
||||
, m_channel(0), m_connected(false)
|
||||
, m_motion_plus_inside(false)
|
||||
{
|
||||
#if defined(__linux__) && HAVE_BLUEZ
|
||||
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
|
||||
|
@ -142,15 +143,16 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
|
|||
rpt.second = (u8)size;
|
||||
memcpy(rpt.first, (u8*)data, size);
|
||||
|
||||
// Convert output DATA packets to SET_REPORT packets.
|
||||
// Nintendo Wiimotes work without this translation, but 3rd
|
||||
// Convert output DATA packets to SET_REPORT packets for non-TR
|
||||
// Wiimotes. Nintendo Wiimotes work without this translation, but 3rd
|
||||
// party ones don't.
|
||||
u8 head = m_motion_plus_inside ? 0xa2 : 0x52;
|
||||
if (rpt.first[0] == 0xa2)
|
||||
{
|
||||
rpt.first[0] = 0x52;
|
||||
rpt.first[0] = head;
|
||||
}
|
||||
|
||||
if (rpt.first[0] == 0x52 && rpt.first[1] == 0x18 && rpt.second == 23)
|
||||
if (rpt.first[0] == head && rpt.first[1] == 0x18 && rpt.second == 23)
|
||||
{
|
||||
m_audio_reports.Push(rpt);
|
||||
return;
|
||||
|
|
|
@ -95,6 +95,7 @@ private:
|
|||
void ThreadFunc();
|
||||
|
||||
bool m_connected;
|
||||
bool m_motion_plus_inside;
|
||||
std::thread m_wiimote_thread;
|
||||
Common::FifoQueue<Report> m_read_reports;
|
||||
Common::FifoQueue<Report> m_write_reports;
|
||||
|
|
|
@ -211,7 +211,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
// Don't do anything if the log is unselected
|
||||
if (LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
|
||||
{
|
||||
const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
||||
const char *pFilename = NULL;
|
||||
if (m_pFileSystem)
|
||||
pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
||||
if (pFilename != NULL)
|
||||
{
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowRead: %s (0x%llx) - (DVDAddr: 0x%llx, Size: 0x%x)",
|
||||
|
@ -233,7 +235,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
|
||||
if (!VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
|
||||
{
|
||||
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
PanicAlertT("DVDLowRead - Fatal Error: failed to read from volume");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -325,10 +327,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
PanicAlertT("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
||||
Size = _BufferOutSize;
|
||||
}
|
||||
|
||||
if (!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
|
||||
if(!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
|
||||
{
|
||||
PanicAlertT("Cant read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||
PanicAlertT("DVDLowUnencryptedRead - Fatal Error: failed to read from volume");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -348,7 +349,9 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
|
|||
case DVDLowSeek:
|
||||
{
|
||||
u64 DVDAddress = Memory::Read_U32(_BufferIn + 0x4) << 2;
|
||||
const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
||||
const char *pFilename = NULL;
|
||||
if (m_pFileSystem)
|
||||
pFilename = m_pFileSystem->GetFileName(DVDAddress);
|
||||
if (pFilename != NULL)
|
||||
{
|
||||
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: %s (0x%llx) - (DVDAddr: 0x%llx)",
|
||||
|
|
|
@ -120,7 +120,7 @@ bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode)
|
|||
{
|
||||
// blindly grab the titleID from the disc - it's unencrypted at:
|
||||
// offset 0x0F8001DC and 0x0F80044C
|
||||
VolumeHandler::RAWReadToPtr((u8*)&m_TitleID, (u64)0x0F8001DC, 8);
|
||||
VolumeHandler::GetVolume()->GetTitleID((u8*)&m_TitleID);
|
||||
m_TitleID = Common::swap64(m_TitleID);
|
||||
}
|
||||
else
|
||||
|
@ -189,11 +189,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
|
||||
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
|
||||
|
||||
const DiscIO::INANDContentLoader& rNANDCOntent = AccessContentDevice(TitleID);
|
||||
const DiscIO::INANDContentLoader& rNANDContent = AccessContentDevice(TitleID);
|
||||
u16 NumberOfPrivateContent = 0;
|
||||
if (rNANDCOntent.IsValid()) // Not sure if dolphin will ever fail this check
|
||||
if (rNANDContent.IsValid()) // Not sure if dolphin will ever fail this check
|
||||
{
|
||||
NumberOfPrivateContent = rNANDCOntent.GetNumEntries();
|
||||
NumberOfPrivateContent = rNANDContent.GetNumEntries();
|
||||
|
||||
if ((u32)(TitleID>>32) == 0x00010000)
|
||||
Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address);
|
||||
|
@ -203,10 +203,10 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
Memory::Write_U32(0, _CommandAddress + 0x4);
|
||||
}
|
||||
else
|
||||
Memory::Write_U32((u32)rNANDCOntent.GetContentSize(), _CommandAddress + 0x4);
|
||||
Memory::Write_U32((u32)rNANDContent.GetContentSize(), _CommandAddress + 0x4);
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLECONTENTSCNT: TitleID: %08x/%08x content count %i",
|
||||
(u32)(TitleID>>32), (u32)TitleID, rNANDCOntent.IsValid() ? NumberOfPrivateContent : (u32)rNANDCOntent.GetContentSize());
|
||||
(u32)(TitleID>>32), (u32)TitleID, rNANDContent.IsValid() ? NumberOfPrivateContent : (u32)rNANDContent.GetContentSize());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -266,24 +266,27 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
}
|
||||
break;
|
||||
|
||||
case IOCTL_ES_OPENCONTENT:
|
||||
{
|
||||
_dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
|
||||
_dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
|
||||
case IOCTL_ES_OPENCONTENT:
|
||||
{
|
||||
_dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1);
|
||||
_dbg_assert_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 0);
|
||||
|
||||
u32 CFD = AccessIdentID++;
|
||||
u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
|
||||
u32 CFD = AccessIdentID++;
|
||||
u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address);
|
||||
|
||||
m_ContentAccessMap[CFD].m_Position = 0;
|
||||
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
|
||||
_dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
|
||||
m_ContentAccessMap[CFD].m_Position = 0;
|
||||
m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index);
|
||||
_dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL);
|
||||
|
||||
Memory::Write_U32(CFD, _CommandAddress + 0x4);
|
||||
if (m_ContentAccessMap[CFD].m_pContent == NULL)
|
||||
CFD = 0xffffffff; //TODO: what is the correct error value here?
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
Memory::Write_U32(CFD, _CommandAddress + 0x4);
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_ES_READCONTENT:
|
||||
{
|
||||
|
@ -383,7 +386,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address);
|
||||
|
||||
char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address);
|
||||
sprintf(Path, "/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
|
||||
sprintf(Path, "/title/%08x/%08x/data", (u32)(TitleID >> 32), (u32)TitleID);
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETTITLEDIR: %s", Path);
|
||||
}
|
||||
|
@ -551,11 +554,6 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
|
||||
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
|
||||
|
||||
// Assert if title is not a disc title and the loader is not valid
|
||||
_dbg_assert_msg_(WII_IPC_ES, ((u32)(TitleID >> 32) == 0x00010000) ||
|
||||
((u32)(TitleID >> 32) == 0x00010004) || Loader.IsValid(),
|
||||
"Loader not valid for TitleID %08x/%08x", (u32)(TitleID >> 32), (u32)TitleID);
|
||||
|
||||
u32 TMDViewCnt = 0;
|
||||
if (Loader.IsValid())
|
||||
{
|
||||
|
@ -687,7 +685,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress)
|
|||
// TODO: actually use this param in when writing to the outbuffer :/
|
||||
MaxCount = Memory::Read_U32(Buffer.InBuffer[1].m_Address);
|
||||
}
|
||||
const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(TitleID);
|
||||
const DiscIO::INANDContentLoader& Loader = AccessContentDevice(TitleID);
|
||||
|
||||
|
||||
INFO_LOG(WII_IPC_ES, "IOCTL_ES_GETSTOREDTMD: title: %08x/%08x buffersize: %i", (u32)(TitleID >> 32), (u32)TitleID, MaxCount);
|
||||
|
@ -1003,7 +1001,7 @@ const DiscIO::INANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice(u6
|
|||
|
||||
m_NANDContent[_TitleID] = &DiscIO::CNANDContentManager::Access().GetNANDLoader(_TitleID);
|
||||
|
||||
_dbg_assert_msg_(WII_IPC_ES, m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
|
||||
_dbg_assert_msg_(WII_IPC_ES, ((u32)(_TitleID >> 32) == 0x00010000) || m_NANDContent[_TitleID]->IsValid(), "NandContent not valid for TitleID %08x/%08x", (u32)(_TitleID >> 32), (u32)_TitleID);
|
||||
return *m_NANDContent[_TitleID];
|
||||
}
|
||||
|
||||
|
@ -1025,11 +1023,10 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
std::string tmdPath = Common::GetTMDFileName(tmdTitleID),
|
||||
dataPath = Common::GetTitleDataPath(tmdTitleID);
|
||||
std::string tmdPath = Common::GetTMDFileName(tmdTitleID);
|
||||
|
||||
File::CreateFullPath(tmdPath);
|
||||
File::CreateFullPath(dataPath);
|
||||
File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID));
|
||||
if(!File::Exists(tmdPath))
|
||||
{
|
||||
File::IOFile _pTMDFile(tmdPath, "wb");
|
||||
|
|
|
@ -401,7 +401,7 @@ void Interpreter::dcbtst(UGeckoInstruction _inst)
|
|||
void Interpreter::dcbz(UGeckoInstruction _inst)
|
||||
{
|
||||
// HACK but works... we think
|
||||
if (!HID0.DCFA)
|
||||
if (HID2.WPE || !HID0.DCFA)
|
||||
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,6 +150,8 @@ public:
|
|||
void GenerateConstantOverflow(bool overflow);
|
||||
void GenerateOverflow();
|
||||
void FinalizeCarryOverflow(bool oe, bool inv = false);
|
||||
void GetCarryEAXAndClear();
|
||||
void FinalizeCarryGenerateOverflowEAX(bool oe, bool inv = false);
|
||||
void GenerateCarry();
|
||||
void GenerateRC();
|
||||
void ComputeRC(const Gen::OpArg & arg);
|
||||
|
@ -177,6 +179,7 @@ public:
|
|||
void mulhwux(UGeckoInstruction inst);
|
||||
void mullwx(UGeckoInstruction inst);
|
||||
void divwux(UGeckoInstruction inst);
|
||||
void divwx(UGeckoInstruction inst);
|
||||
void srawix(UGeckoInstruction inst);
|
||||
void srawx(UGeckoInstruction inst);
|
||||
void addex(UGeckoInstruction inst);
|
||||
|
|
|
@ -311,8 +311,8 @@ static GekkoOPTemplate table31_2[] =
|
|||
{138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}},
|
||||
{491, &Jit64::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{1003, &Jit64::Default}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{491, &Jit64::divwx}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{1003, &Jit64::divwx}, //"divwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{459, &Jit64::divwux}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{971, &Jit64::divwux}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}},
|
||||
{75, &Jit64::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}},
|
||||
|
|
|
@ -73,13 +73,53 @@ void Jit64::FinalizeCarryOverflow(bool oe, bool inv)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Output carry is inverted
|
||||
// Do carry
|
||||
FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
|
||||
JitSetCA();
|
||||
SetJumpTarget(carry1);
|
||||
}
|
||||
}
|
||||
|
||||
void Jit64::GetCarryEAXAndClear()
|
||||
{
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
BTR(32, R(EAX), Imm8(29));
|
||||
}
|
||||
|
||||
// Assumes that XER is in EAX and that the CA bit is clear.
|
||||
void Jit64::FinalizeCarryGenerateOverflowEAX(bool oe, bool inv)
|
||||
{
|
||||
// USES_XER
|
||||
if (oe)
|
||||
{
|
||||
FixupBranch jno = J_CC(CC_NO);
|
||||
// Do carry
|
||||
FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
|
||||
OR(32, R(EAX), Imm32(XER_CA_MASK));
|
||||
SetJumpTarget(carry1);
|
||||
//XER[OV/SO] = 1
|
||||
OR(32, R(EAX), Imm32(XER_SO_MASK | XER_OV_MASK));
|
||||
FixupBranch exit = J();
|
||||
SetJumpTarget(jno);
|
||||
// Do carry
|
||||
FixupBranch carry2 = J_CC(inv ? CC_C : CC_NC);
|
||||
OR(32, R(EAX), Imm32(XER_CA_MASK));
|
||||
SetJumpTarget(carry2);
|
||||
//XER[OV] = 0
|
||||
AND(32, R(EAX), Imm32(~XER_OV_MASK));
|
||||
SetJumpTarget(exit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do carry
|
||||
FixupBranch carry1 = J_CC(inv ? CC_C : CC_NC);
|
||||
OR(32, R(EAX), Imm32(XER_CA_MASK));
|
||||
SetJumpTarget(carry1);
|
||||
}
|
||||
// Dump EAX back into XER
|
||||
MOV(32, M(&PowerPC::ppcState.spr[SPR_XER]), R(EAX));
|
||||
}
|
||||
|
||||
// Assumes that the flags were just set through an addition.
|
||||
void Jit64::GenerateCarry() {
|
||||
// USES_XER
|
||||
|
@ -122,7 +162,10 @@ void Jit64::ComputeRC(const Gen::OpArg & arg) {
|
|||
}
|
||||
else
|
||||
{
|
||||
CMP(32, arg, Imm8(0));
|
||||
if (arg.IsSimpleReg())
|
||||
TEST(32, arg, arg);
|
||||
else
|
||||
CMP(32, arg, Imm8(0));
|
||||
FixupBranch pLesser = J_CC(CC_L);
|
||||
FixupBranch pGreater = J_CC(CC_G);
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[0]), Imm8(0x2)); // _x86Reg == 0
|
||||
|
@ -908,33 +951,31 @@ void Jit64::subfex(UGeckoInstruction inst)
|
|||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, (d == a || d == b), true);
|
||||
|
||||
// Get CA and clear it (along with OV if applicable)
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30));
|
||||
|
||||
// Convert carry to borrow
|
||||
CMC();
|
||||
GetCarryEAXAndClear();
|
||||
|
||||
bool invertedCarry = false;
|
||||
if (d == b)
|
||||
{
|
||||
// Convert carry to borrow
|
||||
CMC();
|
||||
SBB(32, gpr.R(d), gpr.R(a));
|
||||
invertedCarry = true;
|
||||
}
|
||||
else if (d == a)
|
||||
{
|
||||
MOV(32, R(EAX), gpr.R(a));
|
||||
MOV(32, gpr.R(d), gpr.R(b));
|
||||
SBB(32, gpr.R(d), R(EAX));
|
||||
NOT(32, gpr.R(d));
|
||||
ADC(32, gpr.R(d), gpr.R(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, gpr.R(d), gpr.R(b));
|
||||
SBB(32, gpr.R(d), gpr.R(a));
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
NOT(32, gpr.R(d));
|
||||
ADC(32, gpr.R(d), gpr.R(b));
|
||||
}
|
||||
if (inst.Rc) {
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE, true);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE, invertedCarry);
|
||||
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
@ -948,9 +989,7 @@ void Jit64::subfmex(UGeckoInstruction inst)
|
|||
gpr.Lock(a, d);
|
||||
gpr.BindToRegister(d, d == a);
|
||||
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
GetCarryEAXAndClear();
|
||||
if (d != a)
|
||||
{
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
|
@ -961,7 +1000,7 @@ void Jit64::subfmex(UGeckoInstruction inst)
|
|||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
||||
|
@ -974,9 +1013,8 @@ void Jit64::subfzex(UGeckoInstruction inst)
|
|||
|
||||
gpr.Lock(a, d);
|
||||
gpr.BindToRegister(d, d == a);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
if (d != a)
|
||||
{
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
|
@ -987,7 +1025,7 @@ void Jit64::subfzex(UGeckoInstruction inst)
|
|||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
|
@ -1047,17 +1085,39 @@ void Jit64::mulli(UGeckoInstruction inst)
|
|||
INSTRUCTION_START
|
||||
JITDISABLE(Integer)
|
||||
int a = inst.RA, d = inst.RD;
|
||||
u32 imm = inst.SIMM_16;
|
||||
|
||||
if (gpr.R(a).IsImm())
|
||||
{
|
||||
gpr.SetImmediate32(d, (s32)gpr.R(a).offset * (s32)inst.SIMM_16);
|
||||
gpr.SetImmediate32(d, (u32)gpr.R(a).offset * imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.Lock(a, d);
|
||||
gpr.BindToRegister(d, (d == a), true);
|
||||
gpr.KillImmediate(a, true, false);
|
||||
IMUL(32, gpr.RX(d), gpr.R(a), Imm32((u32)(s32)inst.SIMM_16));
|
||||
if (imm == 0)
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
else if(imm == -1)
|
||||
{
|
||||
if (d != a)
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
NEG(32, gpr.R(d));
|
||||
}
|
||||
else if((imm & (imm - 1)) == 0)
|
||||
{
|
||||
u32 shift = 0;
|
||||
if (imm & 0xFFFF0000) shift |= 16;
|
||||
if (imm & 0xFF00FF00) shift |= 8;
|
||||
if (imm & 0xF0F0F0F0) shift |= 4;
|
||||
if (imm & 0xCCCCCCCC) shift |= 2;
|
||||
if (imm & 0xAAAAAAAA) shift |= 1;
|
||||
if (d != a)
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
if (shift)
|
||||
SHL(32, gpr.R(d), Imm8(shift));
|
||||
}
|
||||
else
|
||||
IMUL(32, gpr.RX(d), gpr.R(a), Imm32(imm));
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
|
@ -1081,13 +1141,42 @@ void Jit64::mullwx(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, (d == a || d == b), true);
|
||||
if (d == a) {
|
||||
if (gpr.R(a).IsImm() || gpr.R(b).IsImm())
|
||||
{
|
||||
u32 imm = gpr.R(a).IsImm() ? (u32)gpr.R(a).offset : (u32)gpr.R(b).offset;
|
||||
int src = gpr.R(a).IsImm() ? b : a;
|
||||
if (imm == 0)
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
else if(imm == -1)
|
||||
{
|
||||
if (d != src)
|
||||
MOV(32, gpr.R(d), gpr.R(src));
|
||||
NEG(32, gpr.R(d));
|
||||
}
|
||||
else if((imm & (imm - 1)) == 0 && !inst.OE)
|
||||
{
|
||||
u32 shift = 0;
|
||||
if (imm & 0xFFFF0000) shift |= 16;
|
||||
if (imm & 0xFF00FF00) shift |= 8;
|
||||
if (imm & 0xF0F0F0F0) shift |= 4;
|
||||
if (imm & 0xCCCCCCCC) shift |= 2;
|
||||
if (imm & 0xAAAAAAAA) shift |= 1;
|
||||
if (d != src)
|
||||
MOV(32, gpr.R(d), gpr.R(src));
|
||||
if (shift)
|
||||
SHL(32, gpr.R(d), Imm8(shift));
|
||||
}
|
||||
else
|
||||
IMUL(32, gpr.RX(d), gpr.R(src), Imm32(imm));
|
||||
}
|
||||
else if (d == a)
|
||||
IMUL(32, gpr.RX(d), gpr.R(b));
|
||||
} else if (d == b) {
|
||||
IMUL(32, gpr.RX(d), gpr.R(a));
|
||||
} else {
|
||||
MOV(32, gpr.R(d), gpr.R(b));
|
||||
else if (d == b)
|
||||
IMUL(32, gpr.RX(d), gpr.R(a));
|
||||
else
|
||||
{
|
||||
MOV(32, gpr.R(d), gpr.R(b));
|
||||
IMUL(32, gpr.RX(d), gpr.R(a));
|
||||
}
|
||||
if (inst.OE)
|
||||
{
|
||||
|
@ -1157,6 +1246,103 @@ void Jit64::divwux(UGeckoInstruction inst)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (gpr.R(b).IsImm())
|
||||
{
|
||||
u32 divisor = (u32)gpr.R(b).offset;
|
||||
if (divisor == 0)
|
||||
{
|
||||
gpr.SetImmediate32(d, 0);
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 shift = 31;
|
||||
while(!(divisor & (1 << shift)))
|
||||
shift--;
|
||||
|
||||
if (divisor == (1 << shift))
|
||||
{
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, d == a, true);
|
||||
if (d != a)
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
if (shift)
|
||||
SHR(32, gpr.R(d), Imm8(shift));
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 magic_dividend = 0x100000000ULL << shift;
|
||||
u32 magic = (u32)(magic_dividend / divisor);
|
||||
u32 max_quotient = magic >> shift;
|
||||
|
||||
// Test for failure in round-up method
|
||||
if (((u64)(magic+1) * (max_quotient*divisor-1)) >> (shift + 32) != max_quotient-1)
|
||||
{
|
||||
// If failed, use slower round-down method
|
||||
#ifdef _M_X64
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, d == a, true);
|
||||
MOV(32, R(EAX), Imm32(magic));
|
||||
if (d != a)
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
IMUL(64, gpr.RX(d), R(RAX));
|
||||
ADD(64, gpr.R(d), R(RAX));
|
||||
SHR(64, gpr.R(d), Imm8(shift+32));
|
||||
#else
|
||||
gpr.FlushLockX(EDX);
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, d == a, true);
|
||||
MOV(32, R(EAX), Imm32(magic));
|
||||
MUL(32, gpr.R(a));
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
ADD(32, R(EAX), Imm32(magic));
|
||||
ADC(32, gpr.R(d), R(EDX));
|
||||
if (shift)
|
||||
SHR(32, gpr.R(d), Imm8(shift));
|
||||
gpr.UnlockAllX();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// If success, use faster round-up method
|
||||
#ifdef _M_X64
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(a, true, false);
|
||||
gpr.BindToRegister(d, false, true);
|
||||
if (d == a)
|
||||
{
|
||||
MOV(32, R(EAX), Imm32(magic+1));
|
||||
IMUL(64, gpr.RX(d), R(RAX));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, gpr.R(d), Imm32(magic+1));
|
||||
IMUL(64, gpr.RX(d), gpr.R(a));
|
||||
}
|
||||
SHR(64, gpr.R(d), Imm8(shift+32));
|
||||
#else
|
||||
gpr.FlushLockX(EDX);
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, d == a, true);
|
||||
MOV(32, R(EAX), Imm32(magic+1));
|
||||
MUL(32, gpr.R(a));
|
||||
MOV(32, gpr.R(d), R(EDX));
|
||||
if (shift)
|
||||
SHR(32, gpr.R(d), Imm8(shift));
|
||||
gpr.UnlockAllX();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(false);
|
||||
}
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.FlushLockX(EDX);
|
||||
|
@ -1166,7 +1352,6 @@ void Jit64::divwux(UGeckoInstruction inst)
|
|||
XOR(32, R(EDX), R(EDX));
|
||||
gpr.KillImmediate(b, true, false);
|
||||
CMP(32, gpr.R(b), Imm32(0));
|
||||
// doesn't handle if OE is set, but int doesn't either...
|
||||
FixupBranch not_div_by_zero = J_CC(CC_NZ);
|
||||
MOV(32, gpr.R(d), R(EDX));
|
||||
if (inst.OE)
|
||||
|
@ -1193,6 +1378,80 @@ void Jit64::divwux(UGeckoInstruction inst)
|
|||
}
|
||||
}
|
||||
|
||||
void Jit64::divwx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(Integer)
|
||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||
|
||||
if (gpr.R(a).IsImm() && gpr.R(b).IsImm())
|
||||
{
|
||||
s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset;
|
||||
if( j == 0 || i == 0x80000000 && j == -1)
|
||||
{
|
||||
gpr.SetImmediate32(d, (i >> 31) ^ j);
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.SetImmediate32(d, i / j);
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.FlushLockX(EDX);
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, (d == a || d == b), true);
|
||||
MOV(32, R(EAX), gpr.R(a));
|
||||
CDQ();
|
||||
gpr.BindToRegister(b, true, false);
|
||||
TEST(32, gpr.R(b), gpr.R(b));
|
||||
FixupBranch not_div_by_zero = J_CC(CC_NZ);
|
||||
MOV(32, gpr.R(d), R(EDX));
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(true);
|
||||
}
|
||||
FixupBranch end1 = J();
|
||||
SetJumpTarget(not_div_by_zero);
|
||||
CMP(32, gpr.R(b), R(EDX));
|
||||
FixupBranch not_div_by_neg_one = J_CC(CC_NZ);
|
||||
MOV(32, gpr.R(d), R(EAX));
|
||||
NEG(32, gpr.R(d));
|
||||
FixupBranch no_overflow = J_CC(CC_NO);
|
||||
XOR(32, gpr.R(d), gpr.R(d));
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(true);
|
||||
}
|
||||
FixupBranch end2 = J();
|
||||
SetJumpTarget(not_div_by_neg_one);
|
||||
IDIV(32, gpr.R(b));
|
||||
MOV(32, gpr.R(d), R(EAX));
|
||||
SetJumpTarget(no_overflow);
|
||||
if (inst.OE)
|
||||
{
|
||||
GenerateConstantOverflow(false);
|
||||
}
|
||||
SetJumpTarget(end1);
|
||||
SetJumpTarget(end2);
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
{
|
||||
ComputeRC(gpr.R(d));
|
||||
}
|
||||
}
|
||||
|
||||
void Jit64::addx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
@ -1264,31 +1523,29 @@ void Jit64::addex(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, true);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
ADC(32, gpr.R(d), gpr.R((d == a) ? b : a));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.Lock(a, b, d);
|
||||
gpr.BindToRegister(d, false);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
ADC(32, gpr.R(d), gpr.R(b));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
|
@ -1340,31 +1597,29 @@ void Jit64::addmex(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.Lock(d);
|
||||
gpr.BindToRegister(d, true);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.Lock(a, d);
|
||||
gpr.BindToRegister(d, false);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
ADC(32, gpr.R(d), Imm32(0xFFFFFFFF));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
|
@ -1380,31 +1635,29 @@ void Jit64::addzex(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.Lock(d);
|
||||
gpr.BindToRegister(d, true);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
ADC(32, gpr.R(d), Imm8(0));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
gpr.Lock(a, d);
|
||||
gpr.BindToRegister(d, false);
|
||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
||||
JitClearCAOV(inst.OE);
|
||||
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||
|
||||
GetCarryEAXAndClear();
|
||||
MOV(32, gpr.R(d), gpr.R(a));
|
||||
ADC(32, gpr.R(d), Imm8(0));
|
||||
if (inst.Rc)
|
||||
{
|
||||
GenerateRC();
|
||||
}
|
||||
FinalizeCarryOverflow(inst.OE);
|
||||
FinalizeCarryGenerateOverflowEAX(inst.OE);
|
||||
gpr.UnlockAll();
|
||||
}
|
||||
}
|
||||
|
@ -1581,7 +1834,7 @@ void Jit64::rlwnmx(UGeckoInstruction inst)
|
|||
{
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.BindToRegister(a, true, true);
|
||||
gpr.BindToRegister(a, (a == b || a == s), true);
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
if (a != s)
|
||||
{
|
||||
|
@ -1651,9 +1904,22 @@ void Jit64::srwx(UGeckoInstruction inst)
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.BindToRegister(a, true, true);
|
||||
gpr.BindToRegister(a, (a == b || a == s), true);
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
if (a != s)
|
||||
{
|
||||
MOV(32, gpr.R(a), gpr.R(s));
|
||||
}
|
||||
SHR(64, gpr.R(a), R(ECX));
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
#else
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.BindToRegister(a, (a == b || a == s), true);
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
TEST(32, R(ECX), Imm32(32));
|
||||
if (a != s)
|
||||
|
@ -1666,6 +1932,7 @@ void Jit64::srwx(UGeckoInstruction inst)
|
|||
SHR(32, gpr.R(a), R(ECX));
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
#endif
|
||||
}
|
||||
// Shift of 0 doesn't update flags, so compare manually just in case
|
||||
if (inst.Rc)
|
||||
|
@ -1686,12 +1953,38 @@ void Jit64::slwx(UGeckoInstruction inst)
|
|||
{
|
||||
u32 amount = (u32)gpr.R(b).offset;
|
||||
gpr.SetImmediate32(a, (amount & 0x20) ? 0 : (u32)gpr.R(s).offset << amount);
|
||||
if (inst.Rc)
|
||||
{
|
||||
ComputeRC(gpr.R(a));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.BindToRegister(a, true, true);
|
||||
gpr.BindToRegister(a, (a == b || a == s), true);
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
if (a != s)
|
||||
{
|
||||
MOV(32, gpr.R(a), gpr.R(s));
|
||||
}
|
||||
SHL(64, gpr.R(a), R(ECX));
|
||||
if (inst.Rc)
|
||||
{
|
||||
AND(32, gpr.R(a), gpr.R(a));
|
||||
GenerateRC();
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV(32, gpr.R(a), gpr.R(a));
|
||||
}
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
#else
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.Lock(a, b, s);
|
||||
gpr.BindToRegister(a, (a == b || a == s), true);
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
TEST(32, R(ECX), Imm32(32));
|
||||
if (a != s)
|
||||
|
@ -1704,11 +1997,12 @@ void Jit64::slwx(UGeckoInstruction inst)
|
|||
SHL(32, gpr.R(a), R(ECX));
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
}
|
||||
// Shift of 0 doesn't update flags, so compare manually just in case
|
||||
if (inst.Rc)
|
||||
{
|
||||
ComputeRC(gpr.R(a));
|
||||
// Shift of 0 doesn't update flags, so compare manually just in case
|
||||
if (inst.Rc)
|
||||
{
|
||||
ComputeRC(gpr.R(a));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1720,19 +2014,37 @@ void Jit64::srawx(UGeckoInstruction inst)
|
|||
int a = inst.RA;
|
||||
int b = inst.RB;
|
||||
int s = inst.RS;
|
||||
#ifdef _M_X64
|
||||
gpr.Lock(a, s, b);
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.BindToRegister(a, true, true);
|
||||
gpr.BindToRegister(a, (a == s || a == b), true);
|
||||
JitClearCA();
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
if (a != s)
|
||||
MOV(32, gpr.R(a), gpr.R(s));
|
||||
SHL(64, gpr.R(a), Imm8(32));
|
||||
SAR(64, gpr.R(a), R(ECX));
|
||||
MOV(32, R(EAX), gpr.R(a));
|
||||
SHR(64, gpr.R(a), Imm8(32));
|
||||
TEST(32, gpr.R(a), R(EAX));
|
||||
FixupBranch nocarry = J_CC(CC_Z);
|
||||
JitSetCA();
|
||||
SetJumpTarget(nocarry);
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
#else
|
||||
gpr.Lock(a, s, b);
|
||||
gpr.FlushLockX(ECX);
|
||||
gpr.BindToRegister(a, (a == s || a == b), true);
|
||||
JitClearCA();
|
||||
MOV(32, R(ECX), gpr.R(b));
|
||||
if (a != s)
|
||||
MOV(32, gpr.R(a), gpr.R(s));
|
||||
TEST(32, R(ECX), Imm32(32));
|
||||
FixupBranch topBitSet = J_CC(CC_NZ);
|
||||
LEA(32, EAX, MComplex(gpr.RX(a), gpr.RX(a), 1, 0));
|
||||
XOR(32, R(EAX), R(EAX));
|
||||
SHRD(32, R(EAX), gpr.R(a), R(ECX));
|
||||
SAR(32, gpr.R(a), R(ECX));
|
||||
NOT(32, R(ECX));
|
||||
SHL(32, R(EAX), R(ECX));
|
||||
TEST(32, R(EAX), gpr.R(a));
|
||||
FixupBranch nocarry1 = J_CC(CC_Z);
|
||||
JitSetCA();
|
||||
|
@ -1746,7 +2058,7 @@ void Jit64::srawx(UGeckoInstruction inst)
|
|||
SetJumpTarget(nocarry2);
|
||||
gpr.UnlockAll();
|
||||
gpr.UnlockAllX();
|
||||
|
||||
#endif
|
||||
if (inst.Rc) {
|
||||
ComputeRC(gpr.R(a));
|
||||
}
|
||||
|
|
|
@ -144,43 +144,57 @@ bool CBannerLoaderWii::GetBanner(u32* _pBannerImage)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetName(std::string* _rName)
|
||||
bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::string& s)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (IsValid())
|
||||
{
|
||||
// find Banner type
|
||||
SWiiBanner *pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
// Ensure the string is null-terminating, since the banner format
|
||||
// doesn't require it
|
||||
u16 *src = new u16[COMMENT_SIZE + 1];
|
||||
memcpy(src, &pBanner->m_Comment[index], COMMENT_SIZE * sizeof(u16));
|
||||
src[COMMENT_SIZE] = 0;
|
||||
|
||||
ret = CopyBeUnicodeToString(s, src, COMMENT_SIZE + 1);
|
||||
|
||||
delete [] src;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::wstring& s)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
// find Banner type
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
std::string name;
|
||||
if (CopyBeUnicodeToString(name, pBanner->m_Comment[0], WII_BANNER_COMMENT_SIZE))
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
_rName[i] = name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
std::wstring description;
|
||||
for (int i = 0; i < COMMENT_SIZE; ++i)
|
||||
description.push_back(Common::swap16(pBanner->m_Comment[index][i]));
|
||||
|
||||
s = description;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetName(std::string* _rName)
|
||||
{
|
||||
return GetStringFromComments(NAME_IDX, *_rName);
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetName(std::vector<std::wstring>& _rNames)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
// find Banner type
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
std::wstring temp;
|
||||
for (int i = 0; i < WII_BANNER_COMMENT_SIZE; ++i)
|
||||
{
|
||||
temp.push_back(Common::swap16(pBanner->m_Comment[0][i]));
|
||||
}
|
||||
_rNames.push_back(temp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
std::wstring temp;
|
||||
bool ret = GetStringFromComments(NAME_IDX, temp);
|
||||
_rNames.push_back(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetCompany(std::string& _rCompany)
|
||||
|
@ -191,39 +205,12 @@ bool CBannerLoaderWii::GetCompany(std::string& _rCompany)
|
|||
|
||||
bool CBannerLoaderWii::GetDescription(std::string* _rDescription)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
// find Banner type
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
std::string description;
|
||||
if (CopyBeUnicodeToString(description, pBanner->m_Comment[1], WII_BANNER_COMMENT_SIZE))
|
||||
{
|
||||
for (int i = 0; i< 6; i++)
|
||||
{
|
||||
_rDescription[i] = description;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return GetStringFromComments(DESC_IDX, *_rDescription);
|
||||
}
|
||||
|
||||
bool CBannerLoaderWii::GetDescription(std::wstring& _rDescription)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
// find Banner type
|
||||
SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile;
|
||||
|
||||
std::wstring description;
|
||||
for (int i = 0; i < WII_BANNER_COMMENT_SIZE; ++i)
|
||||
description.push_back(Common::swap16(pBanner->m_Comment[1][i]));
|
||||
|
||||
_rDescription = description;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return GetStringFromComments(DESC_IDX, _rDescription);
|
||||
}
|
||||
|
||||
void CBannerLoaderWii::decode5A3image(u32* dst, u16* src, int width, int height)
|
||||
|
|
|
@ -47,9 +47,18 @@ class CBannerLoaderWii
|
|||
|
||||
private:
|
||||
|
||||
#define WII_BANNER_TEXTURE_SIZE (192 * 64 * 2)
|
||||
#define WII_BANNER_ICON_SIZE ( 48 * 48 * 2)
|
||||
#define WII_BANNER_COMMENT_SIZE 32
|
||||
enum
|
||||
{
|
||||
TEXTURE_SIZE = 192 * 64 * 2,
|
||||
ICON_SIZE = 48 * 48 * 2,
|
||||
COMMENT_SIZE = 32
|
||||
};
|
||||
|
||||
enum CommentIndex
|
||||
{
|
||||
NAME_IDX,
|
||||
DESC_IDX
|
||||
};
|
||||
|
||||
struct SWiiBanner
|
||||
{
|
||||
|
@ -59,9 +68,10 @@ class CBannerLoaderWii
|
|||
u16 m_Speed;
|
||||
u8 m_Unknown[22];
|
||||
|
||||
u16 m_Comment[2][WII_BANNER_COMMENT_SIZE];
|
||||
u8 m_BannerTexture[WII_BANNER_TEXTURE_SIZE];
|
||||
u8 m_IconTexture[8][WII_BANNER_ICON_SIZE];
|
||||
// Not null terminated!
|
||||
u16 m_Comment[2][COMMENT_SIZE];
|
||||
u8 m_BannerTexture[TEXTURE_SIZE];
|
||||
u8 m_IconTexture[8][ICON_SIZE];
|
||||
} ;
|
||||
|
||||
u8* m_pBannerFile;
|
||||
|
@ -69,6 +79,9 @@ class CBannerLoaderWii
|
|||
bool m_IsValid;
|
||||
|
||||
void decode5A3image(u32* dst, u16* src, int width, int height);
|
||||
|
||||
bool GetStringFromComments(const CommentIndex index, std::string& s);
|
||||
bool GetStringFromComments(const CommentIndex index, std::wstring& s);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -191,6 +191,8 @@ const SNANDContent* CNANDContentLoader::GetContentByIndex(int _Index) const
|
|||
|
||||
bool CNANDContentLoader::Initialize(const std::string& _rName)
|
||||
{
|
||||
if (_rName.empty())
|
||||
return false;
|
||||
m_Path = _rName;
|
||||
WiiWAD Wad(_rName);
|
||||
u8* pDataApp = NULL;
|
||||
|
@ -221,7 +223,7 @@ bool CNANDContentLoader::Initialize(const std::string& _rName)
|
|||
File::IOFile pTMDFile(TMDFileName, "rb");
|
||||
if (!pTMDFile)
|
||||
{
|
||||
ERROR_LOG(DISCIO, "CreateFromDirectory: error opening %s",
|
||||
DEBUG_LOG(DISCIO, "CreateFromDirectory: error opening %s",
|
||||
TMDFileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -536,20 +538,14 @@ u64 CNANDContentManager::Install_WiiWAD(std::string &fileName)
|
|||
|
||||
pTMDFile.Close();
|
||||
|
||||
|
||||
|
||||
|
||||
//Extract and copy WAD's ticket to ticket directory
|
||||
std::string TicketFileName = Common::GetTicketFileName(TitleID);
|
||||
|
||||
File::CreateFullPath(TicketFileName);
|
||||
File::IOFile pTicketFile(TicketFileName, "wb");
|
||||
if (!pTicketFile)
|
||||
if (!Add_Ticket(TitleID, ContentLoader.GetTIK(), ContentLoader.GetTIKSize()))
|
||||
{
|
||||
PanicAlertT("WAD installation failed: error creating %s", TicketFileName.c_str());
|
||||
PanicAlertT("WAD installation failed: error creating ticket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ContentLoader.GetTIK())
|
||||
{
|
||||
pTicketFile.WriteBytes(ContentLoader.GetTIK(), ContentLoader.GetTIKSize());
|
||||
}
|
||||
|
||||
cUIDsys::AccessInstance().AddTitle(TitleID);
|
||||
|
@ -558,6 +554,18 @@ u64 CNANDContentManager::Install_WiiWAD(std::string &fileName)
|
|||
return TitleID;
|
||||
}
|
||||
|
||||
bool Add_Ticket(u64 TitleID, const u8 *p_tik, u32 tikSize)
|
||||
{
|
||||
std::string TicketFileName = Common::GetTicketFileName(TitleID);
|
||||
File::CreateFullPath(TicketFileName);
|
||||
File::IOFile pTicketFile(TicketFileName, "wb");
|
||||
if (!pTicketFile || !p_tik)
|
||||
{
|
||||
//PanicAlertT("WAD installation failed: error creating %s", TicketFileName.c_str());
|
||||
return false;
|
||||
}
|
||||
return pTicketFile.WriteBytes(p_tik, tikSize);
|
||||
}
|
||||
|
||||
} // namespace end
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
namespace DiscIO
|
||||
{
|
||||
|
||||
bool Add_Ticket(u64 TitleID, const u8 *p_tik, u32 tikSize);
|
||||
struct SNANDContent
|
||||
{
|
||||
u32 m_ContentID;
|
||||
|
|
|
@ -678,11 +678,8 @@ void CFrame::DoOpen(bool Boot)
|
|||
File::SetCurrentDir(currentDir);
|
||||
}
|
||||
|
||||
if (path.IsEmpty())
|
||||
return;
|
||||
|
||||
// Should we boot a new game or just change the disc?
|
||||
if (Boot)
|
||||
if (Boot && !path.IsEmpty())
|
||||
BootGame(std::string(path.mb_str()));
|
||||
else
|
||||
{
|
||||
|
|
|
@ -448,7 +448,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
|
|||
#else
|
||||
// on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
|
||||
// it returns CP-932, in order to use iconv we need to use CP932
|
||||
wxCSConv SJISConv(L"CP932");
|
||||
wxCSConv SJISConv(wxT("CP932"));
|
||||
#endif
|
||||
|
||||
GameListItem& rISOFile = *m_ISOFiles[_Index];
|
||||
|
@ -468,10 +468,13 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
|
|||
// Set the game's banner in the second column
|
||||
SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex);
|
||||
|
||||
std::wstring wname;
|
||||
const std::wstring& wdescription = rISOFile.GetDescription();
|
||||
std::wstring wstring_name;
|
||||
const std::wstring& wstring_description = rISOFile.GetDescription();
|
||||
std::string company;
|
||||
|
||||
wxString name;
|
||||
wxString description;
|
||||
|
||||
// We show the company string on Gamecube only
|
||||
// On Wii we show the description instead as the company string is empty
|
||||
if (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC)
|
||||
|
@ -482,13 +485,11 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
|
|||
case DiscIO::IVolume::COUNTRY_TAIWAN:
|
||||
case DiscIO::IVolume::COUNTRY_JAPAN:
|
||||
{
|
||||
rISOFile.GetName(wname, -1);
|
||||
wxString name = wxString(rISOFile.GetName(0).c_str(), SJISConv);
|
||||
rISOFile.GetName(wstring_name, -1);
|
||||
name = wxString(rISOFile.GetName(0).c_str(), SJISConv);
|
||||
m_gameList.append(StringFromFormat("%s (J)\n", (const char *)name.c_str()));
|
||||
SetItem(_Index, COLUMN_TITLE, name, -1);
|
||||
SetItem(_Index, COLUMN_NOTES, wxString(company.size() ?
|
||||
company.c_str() : rISOFile.GetDescription(0).c_str(),
|
||||
SJISConv), -1);
|
||||
description = wxString(company.size() ? company.c_str() :
|
||||
rISOFile.GetDescription(0).c_str(), SJISConv);
|
||||
}
|
||||
break;
|
||||
case DiscIO::IVolume::COUNTRY_USA:
|
||||
|
@ -496,28 +497,24 @@ void CGameListCtrl::InsertItemInReportView(long _Index)
|
|||
default:
|
||||
{
|
||||
wxCSConv WindowsCP1252(wxFontMapper::GetEncodingName(wxFONTENCODING_CP1252));
|
||||
rISOFile.GetName(wname, SelectedLanguage);
|
||||
rISOFile.GetName(wstring_name, SelectedLanguage);
|
||||
|
||||
SetItem(_Index, COLUMN_TITLE,
|
||||
wxString(
|
||||
rISOFile.GetName(SelectedLanguage).c_str(), WindowsCP1252),
|
||||
-1);
|
||||
name = wxString(rISOFile.GetName(SelectedLanguage).c_str(), WindowsCP1252);
|
||||
m_gameList.append(StringFromFormat("%s (%c)\n",
|
||||
rISOFile.GetName(SelectedLanguage).c_str(), (rISOFile.GetCountry() == DiscIO::IVolume::COUNTRY_USA)?'U':'E'));
|
||||
SetItem(_Index, COLUMN_NOTES,
|
||||
wxString(company.size() ?
|
||||
company.c_str() :
|
||||
rISOFile.GetDescription(SelectedLanguage).c_str(), WindowsCP1252),
|
||||
-1);
|
||||
description = wxString(company.size() ? company.c_str() :
|
||||
rISOFile.GetDescription(SelectedLanguage).c_str(), WindowsCP1252);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (wname.length())
|
||||
SetItem(_Index, COLUMN_TITLE, wname, -1);
|
||||
if (wdescription.length())
|
||||
SetItem(_Index, COLUMN_NOTES, wdescription, -1);
|
||||
|
||||
if (wstring_name.length())
|
||||
name = wstring_name.c_str();
|
||||
if (wstring_description.length())
|
||||
description = wstring_description.c_str();
|
||||
|
||||
SetItem(_Index, COLUMN_TITLE, name, -1);
|
||||
SetItem(_Index, COLUMN_NOTES, description, -1);
|
||||
|
||||
#ifndef _WIN32
|
||||
// Emulation state
|
||||
|
|
|
@ -78,7 +78,7 @@ void CodeConfigPanel::UpdateCodeList()
|
|||
gcodes_end = m_gcodes.end();
|
||||
for (; gcodes_iter!=gcodes_end; ++gcodes_iter)
|
||||
{
|
||||
m_listbox_gcodes->Append(wxString::FromAscii(gcodes_iter->name.c_str()));
|
||||
m_listbox_gcodes->Append(wxString(gcodes_iter->name.c_str(), *wxConvCurrent));
|
||||
if (gcodes_iter->enabled)
|
||||
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
|||
|
||||
if (sel > -1)
|
||||
{
|
||||
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + wxString::FromAscii(m_gcodes[sel].name.c_str()));
|
||||
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + wxString(m_gcodes[sel].name.c_str(), *wxConvCurrent));
|
||||
|
||||
// notes textctrl
|
||||
m_infobox.textctrl_notes->Clear();
|
||||
|
@ -119,10 +119,10 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
|||
notes_iter = m_gcodes[sel].notes.begin(),
|
||||
notes_end = m_gcodes[sel].notes.end();
|
||||
for (; notes_iter!=notes_end; ++notes_iter)
|
||||
m_infobox.textctrl_notes->AppendText(wxString::FromAscii(notes_iter->c_str()));
|
||||
m_infobox.textctrl_notes->AppendText(wxString(notes_iter->c_str(), *wxConvCurrent));
|
||||
m_infobox.textctrl_notes->ScrollLines(-99); // silly
|
||||
|
||||
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + wxString::FromAscii(m_gcodes[sel].creator.c_str()));
|
||||
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + wxString(m_gcodes[sel].creator.c_str(), *wxConvCurrent));
|
||||
|
||||
// add codes to info listbox
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
|
@ -151,9 +151,18 @@ void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
|
|||
|
||||
std::string gameid = m_gameid;
|
||||
|
||||
// WiiWare are identified by their first four characters
|
||||
if (m_gameid[0] == 'W')
|
||||
|
||||
switch (m_gameid[0])
|
||||
{
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'G':
|
||||
break;
|
||||
default:
|
||||
// All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters
|
||||
gameid = m_gameid.substr(0, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
sf::Http::Request req;
|
||||
req.SetURI("/txt.php?txt=" + gameid);
|
||||
|
|
|
@ -158,7 +158,7 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW
|
|||
std::wstring wname;
|
||||
wxString name;
|
||||
if (OpenGameListItem->GetName(wname))
|
||||
name = wname;
|
||||
name = wname.c_str();
|
||||
else
|
||||
name = wxString(OpenISO->GetName().c_str(), wxConvUTF8);
|
||||
m_Name->SetValue(name);
|
||||
|
@ -1280,7 +1280,7 @@ void CISOProperties::ChangeBannerDetails(int lang)
|
|||
#else
|
||||
// on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
|
||||
// it returns CP-932, in order to use iconv we need to use CP932
|
||||
wxCSConv SJISConv(L"CP932");
|
||||
wxCSConv SJISConv(wxT("CP932"));
|
||||
#endif
|
||||
switch (OpenGameListItem->GetCountry())
|
||||
{
|
||||
|
@ -1288,11 +1288,11 @@ void CISOProperties::ChangeBannerDetails(int lang)
|
|||
case DiscIO::IVolume::COUNTRY_JAPAN:
|
||||
|
||||
if (OpenGameListItem->GetName(wname, -1))
|
||||
shortName = wname;
|
||||
shortName = wname.c_str();
|
||||
else
|
||||
shortName = wxString(OpenGameListItem->GetName(0).c_str(), SJISConv);
|
||||
|
||||
if ((comment = OpenGameListItem->GetDescription()).size() == 0)
|
||||
if ((comment = OpenGameListItem->GetDescription().c_str()).size() == 0)
|
||||
comment = wxString(OpenGameListItem->GetDescription(0).c_str(), SJISConv);
|
||||
maker = wxString(OpenGameListItem->GetCompany().c_str(), SJISConv);
|
||||
break;
|
||||
|
@ -1302,10 +1302,10 @@ void CISOProperties::ChangeBannerDetails(int lang)
|
|||
{
|
||||
wxCSConv WindowsCP1252(wxFontMapper::GetEncodingName(wxFONTENCODING_CP1252));
|
||||
if (OpenGameListItem->GetName(wname, lang))
|
||||
shortName = wname;
|
||||
shortName = wname.c_str();
|
||||
else
|
||||
shortName = wxString(OpenGameListItem->GetName(lang).c_str(), WindowsCP1252);
|
||||
if ((comment = OpenGameListItem->GetDescription()).size() == 0)
|
||||
if ((comment = OpenGameListItem->GetDescription().c_str()).size() == 0)
|
||||
comment = wxString(OpenGameListItem->GetDescription(lang).c_str(), WindowsCP1252);
|
||||
maker = wxString(OpenGameListItem->GetCompany().c_str(), WindowsCP1252);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,14 @@ void LogConfigWindow::CreateGUIControls()
|
|||
_connect_macro_(m_writeConsoleCB, LogConfigWindow::OnWriteConsoleChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
|
||||
m_writeWindowCB = new wxCheckBox(this, wxID_ANY, _("Write to Window"));
|
||||
_connect_macro_(m_writeWindowCB, LogConfigWindow::OnWriteWindowChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
|
||||
m_writeDebuggerCB = NULL;
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
m_writeDebuggerCB = new wxCheckBox(this, wxID_ANY, _("Write to Debugger"));
|
||||
_connect_macro_(m_writeDebuggerCB, LogConfigWindow::OnWriteDebuggerChecked, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
wxButton *btn_toggle_all = new wxButton(this, wxID_ANY, _("Toggle All Log Types"),
|
||||
wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
|
@ -75,7 +83,17 @@ void LogConfigWindow::CreateGUIControls()
|
|||
wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs"));
|
||||
sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1);
|
||||
sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1);
|
||||
sbOutputs->Add(m_writeWindowCB, 0);
|
||||
#ifdef _MSC_VER
|
||||
if (m_writeDebuggerCB)
|
||||
{
|
||||
sbOutputs->Add(m_writeWindowCB, 0, wxDOWN, 1);
|
||||
sbOutputs->Add(m_writeDebuggerCB, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sbOutputs->Add(m_writeWindowCB, 0);
|
||||
}
|
||||
|
||||
wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types"));
|
||||
sbLogTypes->Add(m_checks, 1, wxEXPAND);
|
||||
|
@ -107,6 +125,17 @@ void LogConfigWindow::LoadSettings()
|
|||
m_writeConsoleCB->SetValue(m_writeConsole);
|
||||
ini.Get("Options", "WriteToWindow", &m_writeWindow, true);
|
||||
m_writeWindowCB->SetValue(m_writeWindow);
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
ini.Get("Options", "WriteToDebugger", &m_writeDebugger, true);
|
||||
m_writeDebuggerCB->SetValue(m_writeDebugger);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_writeDebugger = false;
|
||||
}
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
bool log_enabled;
|
||||
|
@ -125,6 +154,10 @@ void LogConfigWindow::SaveSettings()
|
|||
ini.Set("Options", "WriteToFile", m_writeFile);
|
||||
ini.Set("Options", "WriteToConsole", m_writeConsole);
|
||||
ini.Set("Options", "WriteToWindow", m_writeWindow);
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent())
|
||||
ini.Set("Options", "WriteToDebugger", m_writeDebugger);
|
||||
#endif
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
ini.Set("Logs", m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i));
|
||||
ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX));
|
||||
|
@ -183,6 +216,21 @@ void LogConfigWindow::OnWriteWindowChecked(wxCommandEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
void LogConfigWindow::OnWriteDebuggerChecked(wxCommandEvent& event)
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
m_writeDebugger = event.IsChecked();
|
||||
if (m_checks->IsChecked(i))
|
||||
{
|
||||
if (m_writeDebugger)
|
||||
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogManager->GetDebuggerListener());
|
||||
else
|
||||
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogManager->GetDebuggerListener());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LogConfigWindow::OnToggleAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
|
@ -207,12 +255,15 @@ void LogConfigWindow::ToggleLog(int _logType, bool enable)
|
|||
m_LogManager->AddListener(logType, m_LogManager->GetFileListener());
|
||||
if (m_writeConsole)
|
||||
m_LogManager->AddListener(logType, m_LogManager->GetConsoleListener());
|
||||
if (m_writeDebugger)
|
||||
m_LogManager->AddListener(logType, m_LogManager->GetDebuggerListener());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LogManager->RemoveListener(logType, (LogListener *)m_LogWindow);
|
||||
m_LogManager->RemoveListener(logType, m_LogManager->GetFileListener());
|
||||
m_LogManager->RemoveListener(logType, m_LogManager->GetConsoleListener());
|
||||
m_LogManager->RemoveListener(logType, m_LogManager->GetDebuggerListener());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,11 +37,11 @@ public:
|
|||
private:
|
||||
LogManager *m_LogManager;
|
||||
CLogWindow *m_LogWindow;
|
||||
bool m_writeFile, m_writeConsole, m_writeWindow;
|
||||
bool m_writeFile, m_writeConsole, m_writeWindow, m_writeDebugger;
|
||||
bool enableAll;
|
||||
|
||||
// Controls
|
||||
wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB;
|
||||
wxCheckBox *m_writeFileCB, *m_writeConsoleCB, *m_writeWindowCB, *m_writeDebuggerCB;
|
||||
wxCheckListBox* m_checks;
|
||||
wxRadioBox *m_verbosity;
|
||||
|
||||
|
@ -50,6 +50,7 @@ private:
|
|||
void OnWriteFileChecked(wxCommandEvent& event);
|
||||
void OnWriteConsoleChecked(wxCommandEvent& event);
|
||||
void OnWriteWindowChecked(wxCommandEvent& event);
|
||||
void OnWriteDebuggerChecked(wxCommandEvent& event);
|
||||
void OnToggleAll(wxCommandEvent& event);
|
||||
void ToggleLog(int _logType, bool enable);
|
||||
void OnLogCheck(wxCommandEvent& event);
|
||||
|
|
|
@ -56,7 +56,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos,
|
|||
#else
|
||||
// on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
|
||||
// it returns CP-932, in order to use iconv we need to use CP932
|
||||
m_SJISConv = wxCSConv(L"CP932");
|
||||
m_SJISConv = wxCSConv(wxT("CP932"));
|
||||
#endif
|
||||
|
||||
m_LogManager = LogManager::GetInstance();
|
||||
|
@ -85,6 +85,16 @@ void CLogWindow::CreateGUIControls()
|
|||
ini.Get("Options", "WriteToFile", &m_writeFile, false);
|
||||
ini.Get("Options", "WriteToConsole", &m_writeConsole, true);
|
||||
ini.Get("Options", "WriteToWindow", &m_writeWindow, true);
|
||||
#ifdef _MSC_VER
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
ini.Get("Options", "WriteToDebugger", &m_writeDebugger, true);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_writeDebugger = false;
|
||||
}
|
||||
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
|
||||
{
|
||||
bool enable;
|
||||
|
@ -104,6 +114,12 @@ void CLogWindow::CreateGUIControls()
|
|||
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
|
||||
else
|
||||
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
|
||||
|
||||
if (m_writeDebugger && enable)
|
||||
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetDebuggerListener());
|
||||
else
|
||||
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetDebuggerListener());
|
||||
|
||||
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ private:
|
|||
bool m_ignoreLogTimer;
|
||||
LogManager *m_LogManager;
|
||||
std::queue<std::pair<u8, wxString> > msgQueue;
|
||||
bool m_writeFile, m_writeConsole, m_writeWindow, m_LogAccess;
|
||||
bool m_writeFile, m_writeConsole, m_writeWindow, m_writeDebugger, m_LogAccess;
|
||||
|
||||
// Controls
|
||||
wxBoxSizer *sBottom;
|
||||
|
|
|
@ -716,7 +716,7 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card)
|
|||
#else
|
||||
// on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS)
|
||||
// it returns CP-932, in order to use iconv we need to use CP932
|
||||
wxCSConv SJISConv(L"CP932");
|
||||
wxCSConv SJISConv(wxT("CP932"));
|
||||
#endif
|
||||
wxTitle = wxString(title, ascii ? *wxConvCurrent : SJISConv);
|
||||
wxComment = wxString(comment, ascii ? *wxConvCurrent : SJISConv);
|
||||
|
|
|
@ -95,7 +95,7 @@ wxString efb_emulate_format_changes_desc = wxTRANSLATE("Ignore any changes to th
|
|||
wxString efb_copy_desc = wxTRANSLATE("Disable emulation of EFB copies.\nThese are often used for post-processing or render-to-texture effects, so while checking this setting gives a great speedup it almost always also causes issues.\n\nIf unsure, leave this unchecked.");
|
||||
wxString efb_copy_texture_desc = wxTRANSLATE("Store EFB copies in GPU texture objects.\nThis is not so accurate, but it works well enough for most games and gives a great speedup over EFB to RAM.\n\nIf unsure, leave this checked.");
|
||||
wxString efb_copy_ram_desc = wxTRANSLATE("Accurately emulate EFB copies.\nSome games depend on this for certain graphical effects or gameplay functionality.\n\nIf unsure, check EFB to Texture instead.");
|
||||
wxString stc_desc = wxTRANSLATE("The safer you adjust this, the less likely the emulator will be missing any texture updates from RAM.\n\nIf unsure, use the second-fastest value from the right.");
|
||||
wxString stc_desc = wxTRANSLATE("The safer you adjust this, the less likely the emulator will be missing any texture updates from RAM.\n\nIf unsure, use the rightmost value.");
|
||||
wxString wireframe_desc = wxTRANSLATE("Render the scene as a wireframe.\n\nIf unsure, leave this unchecked.");
|
||||
wxString disable_lighting_desc = wxTRANSLATE("Improves performance but causes lighting to disappear in most games.\n\nIf unsure, leave this unchecked.");
|
||||
wxString disable_textures_desc = wxTRANSLATE("Disable texturing.\n\nIf unsure, leave this unchecked.");
|
||||
|
@ -455,18 +455,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
|
|||
wxStaticBoxSizer* const szr_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache"));
|
||||
|
||||
// TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1
|
||||
wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 3, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
|
||||
wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
|
||||
_connect_macro_(stc_slider, VideoConfigDiag::Event_Stc, wxEVT_COMMAND_SLIDER_UPDATED, this);
|
||||
RegisterControl(stc_slider, wxGetTranslation(stc_desc));
|
||||
|
||||
if (vconfig.bSafeTextureCache)
|
||||
{
|
||||
if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
|
||||
else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
|
||||
else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
|
||||
else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
|
||||
}
|
||||
else stc_slider->SetValue(3);
|
||||
if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
|
||||
else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
|
||||
else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
|
||||
else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
|
||||
|
||||
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5);
|
||||
szr_safetex->AddStretchSpacer(1);
|
||||
|
|
|
@ -120,12 +120,7 @@ protected:
|
|||
void Event_Stc(wxCommandEvent &ev)
|
||||
{
|
||||
int samples[] = { 0, 512, 128 };
|
||||
if (ev.GetInt() < 3)
|
||||
{
|
||||
vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
|
||||
vconfig.bSafeTextureCache = true;
|
||||
}
|
||||
else vconfig.bSafeTextureCache = false;
|
||||
vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
|
||||
|
||||
ev.Skip();
|
||||
}
|
||||
|
|
|
@ -263,7 +263,7 @@ bool AVIDump::CreateFile()
|
|||
s_Stream->codec->bit_rate = 400000;
|
||||
s_Stream->codec->width = s_width;
|
||||
s_Stream->codec->height = s_height;
|
||||
s_Stream->codec->time_base = (AVRational){1, VideoInterface::TargetRefreshRate};
|
||||
s_Stream->codec->time_base = (AVRational){1, static_cast<int>(VideoInterface::TargetRefreshRate)};
|
||||
s_Stream->codec->gop_size = 12;
|
||||
s_Stream->codec->pix_fmt = g_Config.bUseFFV1 ? PIX_FMT_BGRA : PIX_FMT_YUV420P;
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ void BPReload()
|
|||
// Cases in which we DON'T want to reload the BP
|
||||
continue;
|
||||
default:
|
||||
BPCmd bp = {i, 0xFFFFFF, ((u32*)&bpmem)[i]};
|
||||
BPCmd bp = {i, 0xFFFFFF, static_cast<int>(((u32*)&bpmem)[i])};
|
||||
BPWritten(bp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,10 +65,10 @@
|
|||
#define BPMEM_UNKOWN_57 0x57
|
||||
#define BPMEM_REVBITS 0x58
|
||||
#define BPMEM_SCISSOROFFSET 0x59
|
||||
#define BPMEM_UNKNOWN_60 0x60
|
||||
#define BPMEM_UNKNOWN_61 0x61
|
||||
#define BPMEM_UNKNOWN_62 0x62
|
||||
#define BPMEM_TEXMODESYNC 0x63
|
||||
#define BPMEM_PRELOAD_ADDR 0x60
|
||||
#define BPMEM_PRELOAD_TMEMEVEN 0x61
|
||||
#define BPMEM_PRELOAD_TMEMODD 0x62
|
||||
#define BPMEM_PRELOAD_MODE 0x63
|
||||
#define BPMEM_LOADTLUT0 0x64
|
||||
#define BPMEM_LOADTLUT1 0x65
|
||||
#define BPMEM_TEXINVALIDATE 0x66
|
||||
|
@ -487,10 +487,10 @@ union TexImage1
|
|||
{
|
||||
struct
|
||||
{
|
||||
u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves
|
||||
u32 cache_width : 3;
|
||||
u32 tmem_even : 15; // tmem line index for even LODs
|
||||
u32 cache_width : 3;
|
||||
u32 cache_height : 3;
|
||||
u32 image_type : 1;
|
||||
u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes)
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
@ -499,7 +499,7 @@ union TexImage2
|
|||
{
|
||||
struct
|
||||
{
|
||||
u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves
|
||||
u32 tmem_odd : 15; // tmem line index for odd LODs
|
||||
u32 cache_width : 3;
|
||||
u32 cache_height : 3;
|
||||
};
|
||||
|
@ -893,6 +893,25 @@ union UPE_Copy
|
|||
}
|
||||
};
|
||||
|
||||
union BPU_PreloadTileInfo
|
||||
{
|
||||
u32 hex;
|
||||
struct {
|
||||
u32 count : 15;
|
||||
u32 type : 2;
|
||||
};
|
||||
};
|
||||
|
||||
struct BPS_TmemConfig
|
||||
{
|
||||
u32 preload_addr;
|
||||
u32 preload_tmem_even;
|
||||
u32 preload_tmem_odd;
|
||||
BPU_PreloadTileInfo preload_tile_info;
|
||||
u32 tlut_src;
|
||||
u32 tlut_dest;
|
||||
u32 texinvalidate;
|
||||
};
|
||||
|
||||
// All of BP memory
|
||||
|
||||
|
@ -951,10 +970,8 @@ struct BPMemory
|
|||
u32 boundbox1;//56
|
||||
u32 unknown7[2];//57,58
|
||||
X10Y10 scissorOffset; //59
|
||||
u32 unknown8[10]; //5a,5b,5c,5d, 5e,5f,60,61, 62, 63 (GXTexModeSync), 0x60-0x63 have to do with preloaded textures?
|
||||
u32 tlutXferSrc; //64
|
||||
u32 tlutXferDest; //65
|
||||
u32 texinvalidate;//66
|
||||
u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f
|
||||
BPS_TmemConfig tmem_config; // 60-66
|
||||
u32 metric; //67
|
||||
FieldMode fieldmode;//68
|
||||
u32 unknown10[7];//69-6F
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "VertexLoader.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "Thread.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
using namespace BPFunctions;
|
||||
|
||||
|
@ -301,14 +302,14 @@ void BPWritten(const BPCmd& bp)
|
|||
|
||||
// TODO - figure out a cleaner way.
|
||||
if (GetConfig(CONFIG_ISWII))
|
||||
ptr = GetPointer(bpmem.tlutXferSrc << 5);
|
||||
ptr = GetPointer(bpmem.tmem_config.tlut_src << 5);
|
||||
else
|
||||
ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
|
||||
ptr = GetPointer((bpmem.tmem_config.tlut_src & 0xFFFFF) << 5);
|
||||
|
||||
if (ptr)
|
||||
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
|
||||
else
|
||||
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
|
||||
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tmem_config.tlut_src, bpmem.tmem_config.tlut_src << 5, (bpmem.tmem_config.tlut_src & 0xFFFFF)<< 5);
|
||||
|
||||
// TODO(ector) : kill all textures that use this palette
|
||||
// Not sure if it's a good idea, though. For now, we hash texture palettes
|
||||
|
@ -466,14 +467,22 @@ void BPWritten(const BPCmd& bp)
|
|||
DEBUG_LOG(VIDEO, "Uknown BP Reg 0x57: %08x", bp.newvalue);
|
||||
break;
|
||||
|
||||
case BPMEM_UNKNOWN_60:
|
||||
case BPMEM_UNKNOWN_61:
|
||||
case BPMEM_UNKNOWN_62:
|
||||
// Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90
|
||||
// Are these related to BBox?
|
||||
case BPMEM_PRELOAD_ADDR:
|
||||
case BPMEM_PRELOAD_TMEMEVEN:
|
||||
case BPMEM_PRELOAD_TMEMODD: // Used when PRELOAD_MODE is set
|
||||
break;
|
||||
|
||||
case BPMEM_TEXMODESYNC: // Always set to 0 when GX_TexModeSync() is called.
|
||||
case BPMEM_PRELOAD_MODE: // Set to 0 when GX_TexModeSync() is called.
|
||||
// if this is different from 0, manual TMEM management is used.
|
||||
if (bp.newvalue != 0)
|
||||
{
|
||||
// NOTE(neobrain): Apparently tmemodd doesn't affect hardware behavior at all (libogc uses it just as a buffer and switches its contents with tmemeven whenever this is called)
|
||||
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
|
||||
u8* ram_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5);
|
||||
u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
u32 size = tmem_cfg.preload_tile_info.count * 32;
|
||||
memcpy(texMem + tmem_addr, ram_ptr, size);
|
||||
}
|
||||
break;
|
||||
|
||||
// ------------------------------------------------
|
||||
|
|
|
@ -311,6 +311,7 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
UCPClearReg tmpCtrl(_Value);
|
||||
m_CPClearReg.Hex = tmpCtrl.Hex;
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x", _Value);
|
||||
SetCpClearRegister();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -677,13 +678,15 @@ void SetCpControlRegister()
|
|||
|
||||
}
|
||||
|
||||
// NOTE: The implementation of this function should be correct, but we intentionally aren't using it at the moment.
|
||||
// We don't emulate proper GP timing anyway at the moment, so this code would just slow down emulation.
|
||||
void SetCpClearRegister()
|
||||
{
|
||||
if (IsOnThread())
|
||||
{
|
||||
if (!m_CPClearReg.ClearFifoUnderflow && m_CPClearReg.ClearFifoOverflow)
|
||||
bProcessFifoToLoWatermark = true;
|
||||
}
|
||||
// if (IsOnThread())
|
||||
// {
|
||||
// if (!m_CPClearReg.ClearFifoUnderflow && m_CPClearReg.ClearFifoOverflow)
|
||||
// bProcessFifoToLoWatermark = true;
|
||||
// }
|
||||
}
|
||||
|
||||
} // end of namespace CommandProcessor
|
||||
|
|
|
@ -158,6 +158,7 @@ void UpdateInterruptsFromVideoBackend(u64 userdata);
|
|||
|
||||
bool AllowIdleSkipping();
|
||||
|
||||
void SetCpClearRegister();
|
||||
void SetCpControlRegister();
|
||||
void SetCpStatusRegister();
|
||||
void SetOverflowStatusFromGatherPipe();
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "Common.h"
|
||||
|
||||
bool SaveTGA(const char* filename, int width, int height, void* pdata);
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
|
||||
bool SaveData(const char* filename, const char* pdata);
|
||||
|
||||
#endif // _IMAGEWRITE_H
|
||||
|
|
|
@ -560,6 +560,10 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType
|
|||
WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS);
|
||||
WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA);
|
||||
WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS);
|
||||
if (ApiType & API_D3D9)
|
||||
{
|
||||
WRITE(p, "uniform float4 "I_VTEXSCALE"[4] : register(c%d);\n", C_VTEXSCALE);
|
||||
}
|
||||
WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS);
|
||||
WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE);
|
||||
WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX);
|
||||
|
@ -1099,9 +1103,15 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType)
|
|||
void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType)
|
||||
{
|
||||
if (ApiType == API_D3D11)
|
||||
WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap);
|
||||
WRITE(p, "%s=Tex%d.Sample(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap);
|
||||
else if (ApiType & API_D3D9)
|
||||
{
|
||||
// D3D9 uses different pixel to texel mapping, so we need to offset our sampling address by half a pixel (assuming native and virtual texture dimensions match each other, otherwise some math is involved).
|
||||
// Read the MSDN article "Directly Mapping Texels to Pixels (Direct3D 9)" for further info.
|
||||
WRITE(p, "%s=tex2D(samp%d, (%s.xy + 0.5f*"I_VTEXSCALE"[%d].%s) * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap/2, (texmap&1)?"zw":"xy", texmap, texswap);
|
||||
}
|
||||
else
|
||||
WRITE(p, "%s=tex2D(samp%d,%s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap);
|
||||
WRITE(p, "%s=tex2D(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap);
|
||||
}
|
||||
|
||||
static const char *tevAlphaFuncsTable[] =
|
||||
|
|
|
@ -24,26 +24,27 @@
|
|||
#define I_KCOLORS "k"
|
||||
#define I_ALPHA "alphaRef"
|
||||
#define I_TEXDIMS "texdim"
|
||||
#define I_VTEXSCALE "vtexscale"
|
||||
#define I_ZBIAS "czbias"
|
||||
#define I_INDTEXSCALE "cindscale"
|
||||
#define I_INDTEXMTX "cindmtx"
|
||||
#define I_FOG "cfog"
|
||||
#define I_PLIGHTS "cLights"
|
||||
#define I_PMATERIALS "cmtrl"
|
||||
#define I_PMATERIALS "cmtrl"
|
||||
|
||||
#define C_COLORMATRIX 0 // 0
|
||||
#define C_COLORS 0 // 0
|
||||
#define C_KCOLORS (C_COLORS + 4) // 4
|
||||
#define C_ALPHA (C_KCOLORS + 4) // 8
|
||||
#define C_TEXDIMS (C_ALPHA + 1) // 9
|
||||
#define C_ZBIAS (C_TEXDIMS + 8) //17
|
||||
#define C_INDTEXSCALE (C_ZBIAS + 2) //19
|
||||
#define C_INDTEXMTX (C_INDTEXSCALE + 2) //21
|
||||
#define C_FOG (C_INDTEXMTX + 6) //27
|
||||
|
||||
#define C_PLIGHTS (C_FOG + 3)
|
||||
#define C_PMATERIALS (C_PLIGHTS + 40)
|
||||
#define C_PENVCONST_END (C_PMATERIALS + 4)
|
||||
#define C_VTEXSCALE (C_TEXDIMS + 8) //17 - virtual texture scaling factor (e.g. custom textures, scaled EFB copies)
|
||||
#define C_ZBIAS (C_VTEXSCALE + 4) //21
|
||||
#define C_INDTEXSCALE (C_ZBIAS + 2) //23
|
||||
#define C_INDTEXMTX (C_INDTEXSCALE + 2) //25
|
||||
#define C_FOG (C_INDTEXMTX + 6) //31
|
||||
#define C_PLIGHTS (C_FOG + 3) //34
|
||||
#define C_PMATERIALS (C_PLIGHTS + 40) //74
|
||||
#define C_PENVCONST_END (C_PMATERIALS + 4) //78
|
||||
#define PIXELSHADERUID_MAX_VALUES 70
|
||||
#define PIXELSHADERUID_MAX_VALUES_SAFE 120
|
||||
|
||||
|
|
|
@ -36,9 +36,11 @@ static bool s_bFogRangeAdjustChanged;
|
|||
static int nLightsChanged[2]; // min,max
|
||||
static float lastRGBAfull[2][4][4];
|
||||
static u8 s_nTexDimsChanged;
|
||||
static u8 s_nVirtualTexScalesChanged;
|
||||
static u8 s_nIndTexScaleChanged;
|
||||
static u32 lastAlpha;
|
||||
static u32 lastTexDims[8]; // width | height << 16 | wrap_s << 28 | wrap_t << 30
|
||||
static float lastVirtualTexScales[16]; // even fields: width ratio; odd fields: height ratio
|
||||
static u32 lastZBias;
|
||||
static int nMaterialsChanged;
|
||||
|
||||
|
@ -61,6 +63,7 @@ void PixelShaderManager::Init()
|
|||
{
|
||||
lastAlpha = 0;
|
||||
memset(lastTexDims, 0, sizeof(lastTexDims));
|
||||
memset(lastVirtualTexScales, 0, sizeof(lastVirtualTexScales));
|
||||
lastZBias = 0;
|
||||
memset(lastRGBAfull, 0, sizeof(lastRGBAfull));
|
||||
Dirty();
|
||||
|
@ -70,6 +73,7 @@ void PixelShaderManager::Dirty()
|
|||
{
|
||||
s_nColorsChanged[0] = s_nColorsChanged[1] = 15;
|
||||
s_nTexDimsChanged = 0xFF;
|
||||
s_nVirtualTexScalesChanged = 0xFF;
|
||||
s_nIndTexScaleChanged = 0xFF;
|
||||
s_nIndTexMtxChanged = 15;
|
||||
s_bAlphaChanged = s_bZBiasChanged = s_bZTextureTypeChanged = s_bDepthRangeChanged = true;
|
||||
|
@ -83,7 +87,7 @@ void PixelShaderManager::Shutdown()
|
|||
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetConstants()
|
||||
void PixelShaderManager::SetConstants(API_TYPE api_type)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
|
@ -109,6 +113,16 @@ void PixelShaderManager::SetConstants()
|
|||
s_nTexDimsChanged = 0;
|
||||
}
|
||||
|
||||
if ((api_type & API_D3D9) && s_nVirtualTexScalesChanged)
|
||||
{
|
||||
for (int i = 0; i < 8; i += 2)
|
||||
{
|
||||
if (s_nVirtualTexScalesChanged & (3<<i))
|
||||
SetPSVirtualTexScalePair(i/2);
|
||||
}
|
||||
s_nVirtualTexScalesChanged = 0;
|
||||
}
|
||||
|
||||
if (s_bAlphaChanged)
|
||||
{
|
||||
SetPSConstant4f(C_ALPHA, (lastAlpha&0xff)/255.0f, ((lastAlpha>>8)&0xff)/255.0f, 0, ((lastAlpha>>16)&0xff)/255.0f);
|
||||
|
@ -338,6 +352,13 @@ void PixelShaderManager::SetPSTextureDims(int texid)
|
|||
SetPSConstant4fv(C_TEXDIMS + texid, fdims);
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetPSVirtualTexScalePair(int texpairid)
|
||||
{
|
||||
PRIM_LOG("vtexscale%d: %f %f %f %f\n", texpairid, lastVirtualTexScales[texpairid*4], lastVirtualTexScales[texpairid*4+1],
|
||||
lastVirtualTexScales[texpairid*4+2], lastVirtualTexScales[texpairid*4+3]);
|
||||
SetPSConstant4fv(C_VTEXSCALE + texpairid, &lastVirtualTexScales[texpairid*4]);
|
||||
}
|
||||
|
||||
// This one is high in profiles (0.5%). TODO: Move conversion out, only store the raw color value
|
||||
// and update it when the shader constant is set, only.
|
||||
void PixelShaderManager::SetColorChanged(int type, int num, bool high)
|
||||
|
@ -376,14 +397,25 @@ void PixelShaderManager::SetDestAlpha(const ConstantAlpha& alpha)
|
|||
}
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt)
|
||||
void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type)
|
||||
{
|
||||
u32 wh = width | (height << 16) | (wraps << 28) | (wrapt << 30);
|
||||
if (lastTexDims[texmapid] != wh)
|
||||
|
||||
bool refresh = lastTexDims[texmapid] != wh;
|
||||
if (api_type & API_D3D9)
|
||||
{
|
||||
lastTexDims[texmapid] = wh;
|
||||
refresh |= (lastVirtualTexScales[texmapid*2] != (float)width / (float)virtual_width);
|
||||
refresh |= (lastVirtualTexScales[texmapid*2+1] != (float)height / (float)virtual_height);
|
||||
}
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
lastTexDims[texmapid] = wh;
|
||||
lastVirtualTexScales[texmapid*2] = (float)width / (float)virtual_width;
|
||||
lastVirtualTexScales[texmapid*2+1] = (float)height / (float)virtual_height;
|
||||
s_nTexDimsChanged |= 1 << texmapid;
|
||||
}
|
||||
s_nVirtualTexScalesChanged |= 1 << texmapid;
|
||||
}
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetZTextureBias(u32 bias)
|
||||
|
|
|
@ -26,18 +26,20 @@
|
|||
class PixelShaderManager
|
||||
{
|
||||
static void SetPSTextureDims(int texid);
|
||||
static void SetPSVirtualTexScalePair(int texpairid);
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Dirty();
|
||||
static void Shutdown();
|
||||
|
||||
static void SetConstants(); // sets pixel shader constants
|
||||
static void SetConstants(API_TYPE api_type); // sets pixel shader constants
|
||||
|
||||
// constant management, should be called after memory is committed
|
||||
static void SetColorChanged(int type, int index, bool high);
|
||||
static void SetAlpha(const AlphaFunc& alpha);
|
||||
static void SetDestAlpha(const ConstantAlpha& alpha);
|
||||
static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt);
|
||||
static void SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type);
|
||||
static void SetZTextureBias(u32 bias);
|
||||
static void SetViewportChanged();
|
||||
static void SetIndMatrixChanged(int matrixidx);
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
|
@ -23,28 +39,19 @@ enum
|
|||
|
||||
TextureCache *g_texture_cache;
|
||||
|
||||
GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
|
||||
GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
|
||||
|
||||
TextureCache::TexCache TextureCache::textures;
|
||||
bool TextureCache::DeferredInvalidate;
|
||||
|
||||
TextureCache::TCacheEntryBase::~TCacheEntryBase()
|
||||
{
|
||||
if (0 == addr)
|
||||
return;
|
||||
|
||||
if (!isRenderTarget && !g_ActiveConfig.bSafeTextureCache)
|
||||
{
|
||||
u32 *const ptr = (u32*)Memory::GetPointer(addr);
|
||||
if (ptr && *ptr == hash)
|
||||
*ptr = oldpixel;
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
if (!temp)
|
||||
temp =(u8*) AllocateAlignedMemory(TEMP_SIZE,16);
|
||||
temp = (u8*)AllocateAlignedMemory(TEMP_SIZE,16);
|
||||
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
|
||||
if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures)
|
||||
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
|
@ -88,12 +95,11 @@ TextureCache::~TextureCache()
|
|||
|
||||
void TextureCache::Cleanup()
|
||||
{
|
||||
TexCache::iterator
|
||||
iter = textures.begin(),
|
||||
tcend = textures.end();
|
||||
TexCache::iterator iter = textures.begin();
|
||||
TexCache::iterator tcend = textures.end();
|
||||
while (iter != tcend)
|
||||
{
|
||||
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
|
||||
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) // TODO: Deleting EFB copies might not be a good idea here...
|
||||
{
|
||||
delete iter->second;
|
||||
textures.erase(iter++);
|
||||
|
@ -135,7 +141,7 @@ void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
|
|||
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
|
||||
if (0 == rangePosition)
|
||||
{
|
||||
iter->second->hash = 0;
|
||||
iter->second->SetHashes(TEXHASH_INVALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,19 +173,16 @@ void TextureCache::ClearRenderTargets()
|
|||
iter = textures.begin(),
|
||||
tcend = textures.end();
|
||||
for (; iter!=tcend; ++iter)
|
||||
iter->second->isRenderTarget = false;
|
||||
iter->second->type = TCET_NORMAL;
|
||||
}
|
||||
|
||||
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)
|
||||
unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem)
|
||||
{
|
||||
// necessary?
|
||||
if (0 == address)
|
||||
return NULL;
|
||||
|
||||
u8* ptr = Memory::GetPointer(address);
|
||||
|
||||
// TexelSizeInNibbles(format)*width*height/16;
|
||||
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
|
||||
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
|
||||
|
@ -188,111 +191,82 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
unsigned int expandedHeight = (height + bsh) & (~bsh);
|
||||
const unsigned int nativeW = width;
|
||||
const unsigned int nativeH = height;
|
||||
bool isPow2;
|
||||
|
||||
u64 hash_value = 0;
|
||||
u64 texHash = 0;
|
||||
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)
|
||||
u64 tlut_hash = TEXHASH_INVALID;
|
||||
|
||||
u32 full_format = texformat;
|
||||
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
|
||||
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
|
||||
bool texture_is_dynamic = false;
|
||||
unsigned int texLevels;
|
||||
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
|
||||
|
||||
const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);
|
||||
|
||||
if (isPaletteTexture)
|
||||
full_format = texformat | (tlutfmt << 16);
|
||||
|
||||
// hires texture loading and texture dumping require accurate hashes
|
||||
if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
|
||||
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);
|
||||
|
||||
tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (isPaletteTexture)
|
||||
{
|
||||
texHash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
|
||||
tlut_hash = GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
if (isPaletteTexture)
|
||||
{
|
||||
// WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
|
||||
// tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
|
||||
// This trick (to change the texID depending on the TLUT addr) is a trick to get around
|
||||
// an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
|
||||
// each other stored in a single texture, and uses the palette to make different characters
|
||||
// visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
|
||||
// we must make sure that texture with different tluts get different IDs.
|
||||
|
||||
const u64 tlutHash = GetHash64(texMem + tlutaddr, palette_size,
|
||||
g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
texHash ^= tlutHash;
|
||||
|
||||
if (g_ActiveConfig.bSafeTextureCache)
|
||||
texID ^= ((u32)tlutHash) ^ (u32)(tlutHash >> 32);
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bSafeTextureCache)
|
||||
hash_value = texHash;
|
||||
// NOTE: For non-paletted textures, texID is equal to the texture address.
|
||||
// A paletted texture, however, may have multiple texIDs assigned though depending on the currently used tlut.
|
||||
// This (changing texID depending on the tlut_hash) is a trick to get around
|
||||
// an issue with Metroid Prime's fonts (it has multiple sets of fonts on each other
|
||||
// stored in a single texture and uses the palette to make different characters
|
||||
// visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
|
||||
// we must make sure that a paletted texture gets assigned multiple IDs for each tlut used.
|
||||
//
|
||||
// TODO: Because texID isn't always the same as the address now, CopyRenderTargetToTexture might be broken now
|
||||
texID ^= ((u32)tlut_hash) ^(u32)(tlut_hash >> 32);
|
||||
tex_hash ^= tlut_hash;
|
||||
}
|
||||
|
||||
TCacheEntryBase *entry = textures[texID];
|
||||
if (entry)
|
||||
{
|
||||
if (!g_ActiveConfig.bSafeTextureCache)
|
||||
{
|
||||
if (entry->isRenderTarget || entry->isDynamic)
|
||||
{
|
||||
if (!g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
hash_value = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
// 1. Calculate reference hash:
|
||||
// calculated from RAM texture data for normal textures. Hashes for paletted textures are modified by tlut_hash. 0 for virtual EFB copies.
|
||||
if (g_ActiveConfig.bCopyEFBToTexture && entry->IsEfbCopy())
|
||||
tex_hash = TEXHASH_INVALID;
|
||||
|
||||
if (isPaletteTexture)
|
||||
{
|
||||
hash_value ^= GetHash64(&texMem[tlutaddr], palette_size,
|
||||
g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hash_value = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hash_value = *(u32*)ptr;
|
||||
}
|
||||
}
|
||||
else if ((entry->isRenderTarget || entry->isDynamic) && g_ActiveConfig.bCopyEFBToTexture)
|
||||
// 2. a) For EFB copies, only the hash and the texture address need to match
|
||||
if (entry->IsEfbCopy() && tex_hash == entry->hash && address == entry->addr)
|
||||
{
|
||||
hash_value = 0;
|
||||
}
|
||||
|
||||
if (((entry->isRenderTarget || entry->isDynamic) && hash_value == entry->hash && address == entry->addr)
|
||||
|| ((address == entry->addr) && (hash_value == entry->hash) && full_format == entry->format && entry->mipLevels == maxlevel))
|
||||
{
|
||||
entry->isDynamic = false;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 2. b) For normal textures, all texture parameters need to match
|
||||
if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
|
||||
entry->num_mipmaps == maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
|
||||
{
|
||||
goto return_entry;
|
||||
}
|
||||
|
||||
// 3. If we reach this line, we'll have to upload the new texture data to VRAM.
|
||||
// If we're lucky, the texture parameters didn't change and we can reuse the internal texture object instead of destroying and recreating it.
|
||||
//
|
||||
// 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->native_width && height == entry->native_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
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's reload the new texture data into the same texture,
|
||||
// instead of destroying it and having to create a new one.
|
||||
// Might speed up movie playback very, very slightly.
|
||||
texture_is_dynamic = (entry->isRenderTarget || entry->isDynamic) && !g_ActiveConfig.bCopyEFBToTexture;
|
||||
|
||||
if (!entry->isRenderTarget &&
|
||||
((!entry->isDynamic && width == entry->realW && height == entry->realH && full_format == entry->format && entry->mipLevels == maxlevel)
|
||||
|| (entry->isDynamic && entry->realW == width && entry->realH == height)))
|
||||
{
|
||||
// reuse the texture
|
||||
}
|
||||
else
|
||||
{
|
||||
// delete the texture and make a new one
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
// delete the texture and make a new one
|
||||
delete entry;
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (g_ActiveConfig.bHiresTextures)
|
||||
{
|
||||
// Load Custom textures
|
||||
|
@ -301,23 +275,24 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
unsigned int newWidth = width;
|
||||
unsigned int newHeight = height;
|
||||
|
||||
sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
|
||||
sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
|
||||
pcfmt = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, temp);
|
||||
|
||||
if (pcfmt != PC_TEX_FMT_NONE)
|
||||
{
|
||||
expandedWidth = width = newWidth;
|
||||
expandedHeight = height = newHeight;
|
||||
|
||||
// TODO: shouldn't generating mips be forced on now?
|
||||
// native mips with a custom texture wouldn't make sense
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled
|
||||
if (pcfmt == PC_TEX_FMT_NONE)
|
||||
pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth,
|
||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth,
|
||||
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
|
||||
bool isPow2;
|
||||
unsigned int texLevels;
|
||||
UseNativeMips = UseNativeMips && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
|
||||
isPow2 = !((width & (width - 1)) || (height & (height - 1)));
|
||||
texLevels = (isPow2 && UseNativeMips && maxlevel) ?
|
||||
GetPow2(std::max(width, height)) : !isPow2;
|
||||
|
@ -329,40 +304,27 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
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 gets changes
|
||||
// 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
|
||||
entry->mipLevels = maxlevel;
|
||||
//
|
||||
// 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...
|
||||
entry->type = TCET_NORMAL;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||
}
|
||||
|
||||
entry->addr = address;
|
||||
entry->format = full_format;
|
||||
entry->size_in_bytes = texture_size;
|
||||
|
||||
entry->virtualW = width;
|
||||
entry->virtualH = height;
|
||||
|
||||
entry->realW = nativeW;
|
||||
entry->realH = nativeH;
|
||||
|
||||
entry->isRenderTarget = false;
|
||||
entry->isNonPow2 = false;
|
||||
entry->isDynamic = texture_is_dynamic;
|
||||
|
||||
entry->oldpixel = *(u32*)ptr;
|
||||
|
||||
if (g_ActiveConfig.bSafeTextureCache || entry->isDynamic)
|
||||
entry->hash = hash_value;
|
||||
else
|
||||
// don't like rand() here
|
||||
entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
|
||||
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
|
||||
entry->SetDimensions(nativeW, nativeH, width, height);
|
||||
entry->hash = tex_hash;
|
||||
if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_NORMAL;
|
||||
else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC;
|
||||
|
||||
// load texture
|
||||
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
|
||||
|
||||
// load mips
|
||||
// load mips - TODO: Loading mipmaps from tmem is untested!
|
||||
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
|
||||
{
|
||||
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
|
||||
|
@ -370,20 +332,31 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
unsigned int level = 1;
|
||||
unsigned int mipWidth = (width + 1) >> 1;
|
||||
unsigned int mipHeight = (height + 1) >> 1;
|
||||
ptr += texture_size;
|
||||
|
||||
u8* ptr_even = NULL, *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];
|
||||
}
|
||||
src_data += texture_size;
|
||||
|
||||
while ((mipHeight || mipWidth) && (level < texLevels))
|
||||
{
|
||||
u8** ptr;
|
||||
if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even;
|
||||
else ptr = &src_data;
|
||||
|
||||
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
||||
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
||||
|
||||
expandedWidth = (currentWidth + bsw) & (~bsw);
|
||||
expandedHeight = (currentHeight + bsh) & (~bsh);
|
||||
|
||||
TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
entry->Load(currentWidth, currentHeight, expandedWidth, level);
|
||||
TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
|
||||
entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
|
||||
|
||||
ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
|
||||
*ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
++level;
|
||||
|
@ -404,7 +377,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
|
|||
|
||||
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(),
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(),
|
||||
(u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
|
||||
(u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
|
||||
|
||||
if (false == File::Exists(szTemp))
|
||||
entry->Save(szTemp);
|
||||
|
@ -426,6 +399,45 @@ return_entry:
|
|||
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
||||
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
|
||||
{
|
||||
// Emulation methods:
|
||||
// - EFB to RAM:
|
||||
// Encodes the requested EFB data at its native resolution to the emulated RAM using shaders.
|
||||
// Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being used as a texture again.
|
||||
// Advantage: CPU can read data from the EFB copy and we don't lose any important updates to the texture
|
||||
// Disadvantage: Encoding+decoding steps often are redundant because only some games read or modify EFB copies before using them as textures.
|
||||
// - EFB to texture:
|
||||
// Copies the requested EFB data to a texture object in VRAM, performing any color conversion using shaders.
|
||||
// Advantage: Works for many games, since in most cases EFB copies aren't read or modified at all before being used as a texture again.
|
||||
// Since we don't do any further encoding or decoding here, this method is much faster.
|
||||
// It also allows enhancing the visual quality by doing scaled EFB copies.
|
||||
// - hybrid EFB copies:
|
||||
// 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to RAM)
|
||||
// 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address range.
|
||||
// If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB copies.
|
||||
// 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB copy was triggered to that address before):
|
||||
// 2a) Entry doesn't exist:
|
||||
// - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture)
|
||||
// - Create a texture cache entry for the target (type = TCET_EC_VRAM)
|
||||
// - Store a hash of the encoded RAM data in the texcache entry.
|
||||
// 2b) Entry exists AND type is TCET_EC_VRAM:
|
||||
// - Like case 2a, but reuse the old texcache entry instead of creating a new one.
|
||||
// 2c) Entry exists AND type is TCET_EC_DYNAMIC:
|
||||
// - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in the existing texcache entry.
|
||||
// - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up deleting it and reloading the data from RAM anyway.
|
||||
// 3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you stored when encoding the EFB data to RAM.
|
||||
// 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created
|
||||
// 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to TCET_EC_DYNAMIC.
|
||||
// Redecode the source RAM data to a VRAM object. The entry basically behaves like a normal texture now.
|
||||
// 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture.
|
||||
// Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture.
|
||||
// Compatibility is as good as EFB to RAM.
|
||||
// Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM.
|
||||
// EFB copy cache depends on accurate texture hashing being enabled. However, with accurate hashing you end up being as slow as without a copy cache anyway.
|
||||
//
|
||||
// Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush which stalls any further CPU processing.
|
||||
//
|
||||
// For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies.
|
||||
|
||||
float colmat[28] = {0};
|
||||
float *const fConstAdd = colmat + 16;
|
||||
float *const ColorMask = colmat + 20;
|
||||
|
@ -472,9 +484,9 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
|||
cbufid = 5;
|
||||
break;
|
||||
|
||||
case 12: // Z16L - copy lower 16 depth bits
|
||||
// expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha)
|
||||
// Used e.g. in Zelda: Skyward Sword
|
||||
case 12: // Z16L - copy lower 16 depth bits
|
||||
// expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha)
|
||||
// Used e.g. in Zelda: Skyward Sword
|
||||
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
|
||||
cbufid = 6;
|
||||
break;
|
||||
|
@ -628,15 +640,15 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
|||
unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w;
|
||||
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;
|
||||
|
||||
bool texture_is_dynamic = false;
|
||||
|
||||
TCacheEntryBase *entry = textures[dstAddr];
|
||||
if (entry)
|
||||
{
|
||||
if ((entry->isRenderTarget && entry->virtualW == scaled_tex_w && entry->virtualH == scaled_tex_h)
|
||||
|| (entry->isDynamic && entry->realW == tex_w && entry->realH == tex_h))
|
||||
if ((entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h)
|
||||
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h))
|
||||
{
|
||||
texture_is_dynamic = entry->isDynamic;
|
||||
scaled_tex_w = tex_w;
|
||||
scaled_tex_h = tex_h;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -646,32 +658,16 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
|
|||
}
|
||||
}
|
||||
|
||||
if (texture_is_dynamic)
|
||||
{
|
||||
scaled_tex_w = tex_w;
|
||||
scaled_tex_h = tex_h;
|
||||
}
|
||||
|
||||
if (NULL == entry)
|
||||
{
|
||||
// create the texture
|
||||
textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
|
||||
|
||||
entry->addr = dstAddr;
|
||||
entry->hash = 0;
|
||||
|
||||
entry->realW = tex_w;
|
||||
entry->realH = tex_h;
|
||||
|
||||
entry->virtualW = scaled_tex_w;
|
||||
entry->virtualH = scaled_tex_h;
|
||||
|
||||
entry->format = dstFormat;
|
||||
entry->mipLevels = 0;
|
||||
|
||||
entry->isRenderTarget = true;
|
||||
entry->isNonPow2 = true;
|
||||
entry->isDynamic = false;
|
||||
// TODO: Using the wrong dstFormat, dumb...
|
||||
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 0);
|
||||
entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
|
||||
entry->SetHashes(TEXHASH_INVALID);
|
||||
entry->type = TCET_EC_VRAM;
|
||||
}
|
||||
|
||||
entry->frameCount = frameCount;
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _TEXTURECACHEBASE_H
|
||||
#define _TEXTURECACHEBASE_H
|
||||
|
@ -14,47 +30,56 @@
|
|||
class TextureCache
|
||||
{
|
||||
public:
|
||||
enum TexCacheEntryType
|
||||
{
|
||||
TCET_NORMAL,
|
||||
TCET_EC_VRAM, // EFB copy which sits in VRAM and is ready to be used
|
||||
TCET_EC_DYNAMIC, // EFB copy which sits in RAM and needs to be decoded before being used
|
||||
};
|
||||
|
||||
struct TCacheEntryBase
|
||||
{
|
||||
// TODO: organize
|
||||
#define TEXHASH_INVALID 0
|
||||
|
||||
// common members
|
||||
u32 addr;
|
||||
u32 size_in_bytes;
|
||||
u64 hash;
|
||||
//u32 paletteHash;
|
||||
u32 oldpixel;
|
||||
//u32 pal_hash;
|
||||
u32 format;
|
||||
|
||||
|
||||
enum TexCacheEntryType type;
|
||||
|
||||
unsigned int num_mipmaps;
|
||||
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
|
||||
unsigned int virtual_width, virtual_height; // Texture dimensions from OUR point of view - for hires textures or scaled EFB copies
|
||||
|
||||
// used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames
|
||||
int frameCount;
|
||||
|
||||
unsigned int realW, realH; // Texture dimensions from the GameCube's point of view
|
||||
unsigned int virtualW, virtualH; // Texture dimensions from OUR point of view
|
||||
// Real and virtual dimensions are usually the same, but may be
|
||||
// different if e.g. we use high-res textures. Then, realW,realH will
|
||||
// be the dimensions of the original GameCube texture and
|
||||
// virtualW,virtualH will be the dimensions of the high-res texture.
|
||||
|
||||
unsigned int mipLevels;
|
||||
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;
|
||||
}
|
||||
|
||||
bool isRenderTarget; // copied from EFB
|
||||
bool isDynamic; // Used for hybrid EFB copies to enable checks for CPU modifications
|
||||
bool isNonPow2; // doesn't seem to be used anywhere
|
||||
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;
|
||||
}
|
||||
|
||||
void SetHashes(u64 hash/*, u32 pal_hash*/)
|
||||
{
|
||||
this->hash = hash;
|
||||
//this->pal_hash = pal_hash;
|
||||
}
|
||||
|
||||
//TCacheEntryBase()
|
||||
//{
|
||||
// // TODO: remove these
|
||||
// isRenderTarget = 0;
|
||||
// hash = 0;
|
||||
// //paletteHash = 0;
|
||||
// oldpixel = 0;
|
||||
// addr = 0;
|
||||
// size_in_bytes = 0;
|
||||
// frameCount = 0;
|
||||
// isNonPow2 = true;
|
||||
// w = 0;
|
||||
// h = 0;
|
||||
// scaledW = 0;
|
||||
// scaledH = 0;
|
||||
//}
|
||||
|
||||
virtual ~TCacheEntryBase();
|
||||
|
||||
|
@ -62,13 +87,15 @@ public:
|
|||
virtual bool Save(const char filename[]) = 0;
|
||||
|
||||
virtual void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level, bool autogen_mips = false) = 0;
|
||||
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
|
||||
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat) = 0;
|
||||
|
||||
int IntersectsMemoryRange(u32 range_address, u32 range_size) const;
|
||||
|
||||
bool IsEfbCopy() { return (type == TCET_EC_VRAM || type == TCET_EC_DYNAMIC); }
|
||||
};
|
||||
|
||||
virtual ~TextureCache(); // needs virtual for DX11 dtor
|
||||
|
@ -87,7 +114,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);
|
||||
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem);
|
||||
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
|
||||
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include "Hash.h"
|
||||
enum
|
||||
{
|
||||
TMEM_SIZE = 1024*1024,
|
||||
HALFTMEM_SIZE = 512*1024
|
||||
TMEM_SIZE = 1024*1024,
|
||||
TMEM_LINE_SIZE = 32,
|
||||
};
|
||||
extern GC_ALIGNED16(u8 texMem[TMEM_SIZE]);
|
||||
|
||||
|
|
|
@ -57,12 +57,8 @@ void VideoConfig::Load(const char *ini_file)
|
|||
iniFile.Get("Settings", "Crop", &bCrop, false);
|
||||
iniFile.Get("Settings", "UseXFB", &bUseXFB, 0);
|
||||
iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0);
|
||||
iniFile.Get("Settings", "UseNativeMips", &bUseNativeMips, false);
|
||||
|
||||
iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, true); // Settings
|
||||
//Safe texture cache params
|
||||
iniFile.Get("Settings", "UseNativeMips", &bUseNativeMips, false);
|
||||
iniFile.Get("Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples,128);
|
||||
|
||||
iniFile.Get("Settings", "ShowFPS", &bShowFPS, false); // Settings
|
||||
iniFile.Get("Settings", "ShowInputDisplay", &bShowInputDisplay, false);
|
||||
iniFile.Get("Settings", "OverlayStats", &bOverlayStats, false);
|
||||
|
@ -134,7 +130,6 @@ void VideoConfig::GameIniLoad(const char *ini_file)
|
|||
iniFile.GetIfExists("Video_Settings", "UseXFB", &bUseXFB);
|
||||
iniFile.GetIfExists("Video_Settings", "UseRealXFB", &bUseRealXFB);
|
||||
iniFile.GetIfExists("Video_Settings", "UseNativeMips", &bUseNativeMips);
|
||||
iniFile.GetIfExists("Video_Settings", "SafeTextureCache", &bSafeTextureCache);
|
||||
iniFile.GetIfExists("Video_Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples);
|
||||
iniFile.GetIfExists("Video_Settings", "DLOptimize", &iCompileDLsLevel);
|
||||
iniFile.GetIfExists("Video_Settings", "HiresTextures", &bHiresTextures);
|
||||
|
@ -196,11 +191,7 @@ void VideoConfig::Save(const char *ini_file)
|
|||
iniFile.Set("Settings", "UseXFB", bUseXFB);
|
||||
iniFile.Set("Settings", "UseRealXFB", bUseRealXFB);
|
||||
iniFile.Set("Settings", "UseNativeMips", bUseNativeMips);
|
||||
|
||||
iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache);
|
||||
//safe texture cache params
|
||||
iniFile.Set("Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
|
||||
|
||||
iniFile.Set("Settings", "ShowFPS", bShowFPS);
|
||||
iniFile.Set("Settings", "ShowInputDisplay", bShowInputDisplay);
|
||||
iniFile.Set("Settings", "OverlayStats", bOverlayStats);
|
||||
|
@ -279,7 +270,6 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
|
|||
SET_IF_DIFFERS("Video_Settings", "UseXFB", bUseXFB);
|
||||
SET_IF_DIFFERS("Video_Settings", "UseRealXFB", bUseRealXFB);
|
||||
SET_IF_DIFFERS("Video_Settings", "UseNativeMips", bUseNativeMips);
|
||||
SET_IF_DIFFERS("Video_Settings", "SafeTextureCache", bSafeTextureCache);
|
||||
SET_IF_DIFFERS("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
|
||||
SET_IF_DIFFERS("Video_Settings", "DLOptimize", iCompileDLsLevel);
|
||||
SET_IF_DIFFERS("Video_Settings", "HiresTextures", bHiresTextures);
|
||||
|
|
|
@ -129,7 +129,6 @@ struct VideoConfig
|
|||
bool bOSDHotKey;
|
||||
bool bCopyEFBToTexture;
|
||||
bool bCopyEFBScaled;
|
||||
bool bSafeTextureCache;
|
||||
int iSafeTextureCache_ColorSamples;
|
||||
int iPhackvalue[4];
|
||||
std::string sPhackvalue[2];
|
||||
|
|
|
@ -552,20 +552,22 @@ static const unsigned int ps_constant_offset_table[] = {
|
|||
16, 20, 24, 28, // C_KCOLORS, 16
|
||||
32, // C_ALPHA, 4
|
||||
36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32
|
||||
68, 72, // C_ZBIAS, 8
|
||||
76, 80, // C_INDTEXSCALE, 8
|
||||
84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24
|
||||
108, 112, 116, // C_FOG, 12
|
||||
120, 124, 128, 132, 136, // C_PLIGHTS0, 20
|
||||
140, 144, 148, 152, 156, // C_PLIGHTS1, 20
|
||||
160, 164, 168, 172, 176, // C_PLIGHTS2, 20
|
||||
180, 184, 188, 192, 196, // C_PLIGHTS3, 20
|
||||
200, 204, 208, 212, 216, // C_PLIGHTS4, 20
|
||||
220, 224, 228, 232, 236, // C_PLIGHTS5, 20
|
||||
240, 244, 248, 252, 256, // C_PLIGHTS6, 20
|
||||
260, 264, 268, 272, 276, // C_PLIGHTS7, 20
|
||||
280, 284, 288, 292 // C_PMATERIALS, 16
|
||||
68, 72, 76, 80, // C_VTEXSCALE, 16 (unused)
|
||||
84, 88, // C_ZBIAS, 8
|
||||
92, 96, // C_INDTEXSCALE, 8
|
||||
100, 104, 108, 112, 116, 120, // C_INDTEXMTX, 24
|
||||
124, 128, 132, // C_FOG, 12
|
||||
136, 140, 144, 148, 152, // C_PLIGHTS0, 20
|
||||
156, 160, 164, 168, 172, // C_PLIGHTS1, 20
|
||||
176, 180, 184, 188, 192, // C_PLIGHTS2, 20
|
||||
196, 200, 204, 208, 212, // C_PLIGHTS3, 20
|
||||
216, 220, 224, 228, 232, // C_PLIGHTS4, 20
|
||||
236, 240, 244, 248, 252, // C_PLIGHTS5, 20
|
||||
256, 260, 264, 268, 272, // C_PLIGHTS6, 20
|
||||
276, 280, 284, 288, 292, // C_PLIGHTS7, 20
|
||||
296, 300, 304, 308, // C_PMATERIALS, 16
|
||||
};
|
||||
|
||||
void Renderer::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
psconstants[ps_constant_offset_table[const_number] ] = f1;
|
||||
|
|
|
@ -695,15 +695,18 @@ void Renderer::UpdateViewport(Matrix44& vpCorrection)
|
|||
int Ht = intendedHt;
|
||||
if (Y + Ht > GetTargetHeight())
|
||||
Ht = GetTargetHeight() - Y;
|
||||
|
||||
|
||||
// If GX viewport is off the render target, we must clamp our viewport
|
||||
// within the bounds. Use the correction matrix to compensate.
|
||||
ViewportCorrectionMatrix(vpCorrection,
|
||||
intendedX, intendedY, intendedWd, intendedHt,
|
||||
X, Y, Wd, Ht);
|
||||
(float)intendedX, (float)intendedY,
|
||||
(float)intendedWd, (float)intendedHt,
|
||||
(float)X, (float)Y,
|
||||
(float)Wd, (float)Ht);
|
||||
|
||||
// Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht,
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)X, (float)Y,
|
||||
(float)Wd, (float)Ht,
|
||||
0.f, // (xfregs.viewport.farZ - xfregs.viewport.zRange) / 16777216.0f;
|
||||
1.f); // xfregs.viewport.farZ / 16777216.0f;
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
@ -748,7 +751,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
|||
else if (convtype == 2) pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true);
|
||||
else
|
||||
{
|
||||
PanicAlert("Trying to reinterpret pixel data with unsupported conversion type %d", convtype);
|
||||
ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1106,12 +1109,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
DLCache::ProgressiveCleanup();
|
||||
TextureCache::Cleanup();
|
||||
|
||||
// reload textures if these settings changed
|
||||
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
|
||||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
// Reload textures if this settings changes
|
||||
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
TextureCache::Invalidate(false);
|
||||
|
||||
// Enable any configuration changes
|
||||
// Enable configuration changes
|
||||
UpdateActiveConfig();
|
||||
|
||||
SetWindowSize(fbWidth, fbHeight);
|
||||
|
@ -1428,4 +1430,4 @@ void Renderer::SetInterlacingMode()
|
|||
// TODO
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
} // namespace DX11
|
||||
|
|
|
@ -102,12 +102,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat)
|
||||
{
|
||||
if (!isDynamic || g_ActiveConfig.bCopyEFBToTexture)
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// stretch picture with increased internal resolution
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtualW, (float)virtualH);
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtual_width, (float)virtual_height);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
// set transformation
|
||||
|
@ -149,17 +149,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
if (!g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
u8* dst = Memory::GetPointer(dstAddr);
|
||||
size_t encodeSize = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
|
||||
hash = GetHash64(dst, encodeSize, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
{
|
||||
// If the texture in RAM is already in the texture cache,
|
||||
// do not copy it again as it has not changed.
|
||||
if (TextureCache::Find(dstAddr, hash))
|
||||
return;
|
||||
}
|
||||
size_t encoded_size = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
|
||||
|
||||
TextureCache::MakeRangeDynamic(dstAddr, encodeSize);
|
||||
hash = GetHash64(dst, (int)encoded_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -228,12 +228,13 @@ void VertexManager::vFlush()
|
|||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||
(tex.texMode1[i&3].max_lod >> 4));
|
||||
tex.texMode1[i&3].max_lod >> 4,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
{
|
||||
// 0s are probably for no manual wrapping needed.
|
||||
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
|
||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, tentry->virtual_width, tentry->virtual_height, 0, 0, API_D3D11);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "error loading texture");
|
||||
|
@ -242,7 +243,7 @@ void VertexManager::vFlush()
|
|||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(API_D3D11);
|
||||
|
||||
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
|
||||
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||
|
|
|
@ -434,15 +434,13 @@ void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
|
|||
|
||||
// Fills a certain area of the current render target with the specified color
|
||||
// Z buffer disabled; destination coordinates normalized to (-1;1)
|
||||
void drawColorQuad(int DestWidth, int DestHeight, u32 Color, float x1, float y1, float x2, float y2)
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
float dw = 1.f / (float)DestWidth;
|
||||
float dh = 1.f / (float)DestHeight;
|
||||
struct CQVertex { float x, y, z, rhw; u32 col; } coords[4] = {
|
||||
{ x1-dw, y2+dh, 0.f, 1.f, Color },
|
||||
{ x2-dw, y2+dh, 0.f, 1.f, Color },
|
||||
{ x1-dw, y1+dh, 0.f, 1.f, Color },
|
||||
{ x2-dw, y1+dh, 0.f, 1.f, Color },
|
||||
{ x1, y2, 0.f, 1.f, Color },
|
||||
{ x2, y2, 0.f, 1.f, Color },
|
||||
{ x1, y1, 0.f, 1.f, Color },
|
||||
{ x2, y1, 0.f, 1.f, Color },
|
||||
};
|
||||
dev->SetVertexShader(VertexShaderCache::GetClearVertexShader());
|
||||
dev->SetPixelShader(PixelShaderCache::GetClearProgram());
|
||||
|
@ -451,15 +449,13 @@ void drawColorQuad(int DestWidth, int DestHeight, u32 Color, float x1, float y1,
|
|||
RestoreShaders();
|
||||
}
|
||||
|
||||
void drawClearQuad(int DestWidth, int DestHeight, u32 Color, float z, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader)
|
||||
void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader)
|
||||
{
|
||||
float dw = 1.f / (float)DestWidth;
|
||||
float dh = 1.f / (float)DestHeight;
|
||||
struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = {
|
||||
{-1.0f-dw, 1.0f+dh, z, 1.0f, Color},
|
||||
{ 1.0f-dw, 1.0f+dh, z, 1.0f, Color},
|
||||
{ 1.0f-dw, -1.0f+dh, z, 1.0f, Color},
|
||||
{-1.0f-dw, -1.0f+dh, z, 1.0f, Color}
|
||||
{-1.0f, 1.0f, z, 1.0f, Color},
|
||||
{ 1.0f, 1.0f, z, 1.0f, Color},
|
||||
{ 1.0f, -1.0f, z, 1.0f, Color},
|
||||
{-1.0f, -1.0f, z, 1.0f, Color}
|
||||
};
|
||||
dev->SetVertexShader(Vshader);
|
||||
dev->SetPixelShader(PShader);
|
||||
|
|
|
@ -82,8 +82,8 @@ namespace D3D
|
|||
IDirect3DPixelShader9 *PShader,
|
||||
IDirect3DVertexShader9 *Vshader,
|
||||
float Gamma = 1.0f);
|
||||
void drawClearQuad(int DestWidth, int DestHeight, u32 Color, float z, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader);
|
||||
void drawColorQuad(int DestWidth, int DestHeight, u32 Color, float x1, float y1, float x2, float y2);
|
||||
void drawClearQuad(u32 Color, float z, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader);
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2);
|
||||
|
||||
void SaveRenderStates();
|
||||
void RestoreRenderStates();
|
||||
|
|
|
@ -622,7 +622,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
|||
{
|
||||
// TODO: Speed this up by batching pokes?
|
||||
ResetAPIState();
|
||||
D3D::drawColorQuad(GetTargetWidth(), GetTargetHeight(), poke_data,
|
||||
D3D::drawColorQuad(poke_data,
|
||||
(float)RectToLock.left * 2.f / (float)Renderer::GetTargetWidth() - 1.f,
|
||||
- (float)RectToLock.top * 2.f / (float)Renderer::GetTargetHeight() + 1.f,
|
||||
(float)RectToLock.right * 2.f / (float)Renderer::GetTargetWidth() - 1.f,
|
||||
|
@ -747,7 +747,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
|||
vp.MinZ = 0.0;
|
||||
vp.MaxZ = 1.0;
|
||||
D3D::dev->SetViewport(&vp);
|
||||
D3D::drawClearQuad(GetTargetWidth(), GetTargetHeight(), color, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
|
||||
D3D::drawClearQuad(color, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
|
@ -761,7 +761,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
|||
else if (convtype == 2) pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8();
|
||||
else
|
||||
{
|
||||
PanicAlert("Trying to reinterpret pixel data with unsupported conversion type %d", convtype);
|
||||
ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -896,7 +896,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
D3D::dev->SetViewport(&vp);
|
||||
D3D::drawClearQuad(GetTargetWidth(), GetTargetHeight(), 0, 1.0, PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
|
||||
D3D::drawClearQuad(0, 1.0, PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1114,12 +1114,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
DLCache::ProgressiveCleanup();
|
||||
TextureCache::Cleanup();
|
||||
|
||||
// reload textures if these settings changed
|
||||
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
|
||||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
// Reload textures if these settings changed
|
||||
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
TextureCache::Invalidate(false);
|
||||
|
||||
// Enable any configuration changes
|
||||
// Enable configuration changes
|
||||
UpdateActiveConfig();
|
||||
|
||||
SetWindowSize(fbWidth, fbHeight);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Statistics.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Hash.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
#include "CommonPaths.h"
|
||||
#include "FileUtil.h"
|
||||
|
@ -78,7 +79,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
FramebufferManager::GetEFBDepthTexture() :
|
||||
FramebufferManager::GetEFBColorTexture();
|
||||
|
||||
if (!isDynamic || g_ActiveConfig.bCopyEFBToTexture)
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
||||
texture->GetSurfaceLevel(0, &Rendersurf);
|
||||
|
@ -90,15 +91,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
// Stretch picture with increased internal resolution
|
||||
vp.X = 0;
|
||||
vp.Y = 0;
|
||||
vp.Width = virtualW;
|
||||
vp.Height = virtualH;
|
||||
vp.Width = virtual_width;
|
||||
vp.Height = virtual_height;
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
D3D::dev->SetViewport(&vp);
|
||||
RECT destrect;
|
||||
destrect.bottom = virtualH;
|
||||
destrect.bottom = virtual_height;
|
||||
destrect.left = 0;
|
||||
destrect.right = virtualW;
|
||||
destrect.right = virtual_width;
|
||||
destrect.top = 0;
|
||||
|
||||
PixelShaderManager::SetColorMatrix(colmat); // set transformation
|
||||
|
@ -133,7 +134,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
|
||||
D3D::drawShadedTexQuad(read_texture, &sourcerect,
|
||||
Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
|
||||
virtualW, virtualH,
|
||||
virtual_width, virtual_height,
|
||||
// TODO: why is D3DFMT_D24X8 singled out here? why not D3DFMT_D24X4S4/D24S8/D24FS8/D32/D16/D15S1 too, or none of them?
|
||||
PixelShaderCache::GetDepthMatrixProgram(SSAAMode, (srcFormat == PIXELFMT_Z24) && bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8),
|
||||
VertexShaderCache::GetSimpleVertexShader(SSAAMode));
|
||||
|
@ -143,16 +144,25 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
|
||||
if (!g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
hash = TextureConverter::EncodeToRamFromTexture(
|
||||
addr,
|
||||
read_texture,
|
||||
Renderer::GetTargetWidth(),
|
||||
Renderer::GetTargetHeight(),
|
||||
srcFormat == PIXELFMT_Z24,
|
||||
isIntensity,
|
||||
dstFormat,
|
||||
scaleByHalf,
|
||||
srcRect);
|
||||
int encoded_size = TextureConverter::EncodeToRamFromTexture(
|
||||
addr,
|
||||
read_texture,
|
||||
Renderer::GetTargetWidth(),
|
||||
Renderer::GetTargetHeight(),
|
||||
srcFormat == PIXELFMT_Z24,
|
||||
isIntensity,
|
||||
dstFormat,
|
||||
scaleByHalf,
|
||||
srcRect);
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
}
|
||||
|
||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
||||
|
|
|
@ -252,10 +252,10 @@ void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 sr
|
|||
|
||||
s_texConvReadSurface = TrnBuffers[index].ReadSurface;
|
||||
Rendersurf = TrnBuffers[index].RenderSurface;
|
||||
|
||||
|
||||
hr = D3D::dev->SetDepthStencilSurface(NULL);
|
||||
hr = D3D::dev->SetRenderTarget(0, Rendersurf);
|
||||
|
||||
|
||||
if (linearFilter)
|
||||
{
|
||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
|
@ -290,7 +290,7 @@ void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 sr
|
|||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
||||
// .. and then read back the results.
|
||||
// TODO: make this less slow.
|
||||
|
||||
|
||||
hr = D3D::dev->GetRenderTargetData(Rendersurf,s_texConvReadSurface);
|
||||
|
||||
D3DLOCKED_RECT drect;
|
||||
|
@ -313,76 +313,7 @@ void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 sr
|
|||
hr = s_texConvReadSurface->UnlockRect();
|
||||
}
|
||||
|
||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
if (bFromZBuffer)
|
||||
{
|
||||
format |= _GX_TF_ZTF;
|
||||
if (copyfmt == 11)
|
||||
format = GX_TF_Z16;
|
||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
||||
format |= _GX_TF_CTF;
|
||||
}
|
||||
else
|
||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
||||
format |= _GX_TF_CTF;
|
||||
|
||||
LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format);
|
||||
if (!texconv_shader)
|
||||
return;
|
||||
|
||||
u8 *dest_ptr = Memory::GetPointer(address);
|
||||
|
||||
LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? FramebufferManager::GetEFBDepthTexture() : FramebufferManager::GetEFBColorTexture();
|
||||
int width = (source.right - source.left) >> bScaleByHalf;
|
||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
||||
|
||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
||||
|
||||
// Invalidate any existing texture covering this memory range.
|
||||
// TODO - don't delete the texture if it already exists, just replace the contents.
|
||||
TextureCache::InvalidateRange(address, size_in_bytes);
|
||||
|
||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
||||
|
||||
// only copy on cache line boundaries
|
||||
// extra pixels are copied but not displayed in the resulting texture
|
||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
||||
|
||||
float sampleStride = bScaleByHalf ? 2.f : 1.f;
|
||||
TextureConversionShader::SetShaderParameters(
|
||||
(float)expandedWidth,
|
||||
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
|
||||
(float)Renderer::EFBToScaledX(source.left),
|
||||
(float)Renderer::EFBToScaledY(source.top),
|
||||
Renderer::EFBToScaledXf(sampleStride),
|
||||
Renderer::EFBToScaledYf(sampleStride),
|
||||
(float)Renderer::GetTargetWidth(),
|
||||
(float)Renderer::GetTargetHeight());
|
||||
|
||||
TargetRectangle scaledSource;
|
||||
scaledSource.top = 0;
|
||||
scaledSource.bottom = expandedHeight;
|
||||
scaledSource.left = 0;
|
||||
scaledSource.right = expandedWidth / samples;
|
||||
int cacheBytes = 32;
|
||||
if ((format & 0x0f) == 6)
|
||||
cacheBytes = 64;
|
||||
|
||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
||||
g_renderer->ResetAPIState();
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0,1.0f);
|
||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
int EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
|
@ -440,16 +371,7 @@ u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 So
|
|||
|
||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0,1.0f);
|
||||
u64 hash = GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
{
|
||||
// If the texture in RAM is already in the texture cache, do not copy it again as it has not changed.
|
||||
if (TextureCache::Find(address, hash))
|
||||
return hash;
|
||||
}
|
||||
|
||||
TextureCache::MakeRangeDynamic(address,size_in_bytes);
|
||||
return hash;
|
||||
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
|
||||
}
|
||||
|
||||
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight,float Gamma)
|
||||
|
@ -490,7 +412,7 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE
|
|||
destTexture->GetSurfaceLevel(0,&Rendersurf);
|
||||
D3D::dev->SetDepthStencilSurface(NULL);
|
||||
D3D::dev->SetRenderTarget(0, Rendersurf);
|
||||
|
||||
|
||||
D3DVIEWPORT9 vp;
|
||||
|
||||
// Stretch picture with increased internal resolution
|
||||
|
|
|
@ -35,15 +35,13 @@ namespace TextureConverter
|
|||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
||||
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
||||
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight,float Gamma);
|
||||
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture);
|
||||
|
||||
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
// returns size of the encoded data (in bytes)
|
||||
int EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -137,12 +137,13 @@ void VertexManager::vFlush()
|
|||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips,
|
||||
(tex.texMode1[i&3].max_lod >> 4));
|
||||
tex.texMode1[i&3].max_lod >> 4,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
{
|
||||
// 0s are probably for no manual wrapping needed.
|
||||
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
|
||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, tentry->virtual_width, tentry->virtual_height, 0, 0, API_D3D9);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "error loading texture");
|
||||
|
@ -151,7 +152,7 @@ void VertexManager::vFlush()
|
|||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(API_D3D9);
|
||||
|
||||
if (!PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components))
|
||||
{
|
||||
|
|
|
@ -1394,8 +1394,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
|||
g_Config.iSaveTargetId = 0;
|
||||
|
||||
// reload textures if these settings changed
|
||||
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
|
||||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
|
||||
TextureCache::Invalidate(false);
|
||||
|
||||
if (g_Config.bCopyEFBToTexture != g_ActiveConfig.bCopyEFBToTexture)
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "Globals.h"
|
||||
#include "Hash.h"
|
||||
#include "HiresTextures.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "PixelShaderCache.h"
|
||||
|
@ -124,7 +125,7 @@ bool TextureCache::TCacheEntry::Save(const char filename[])
|
|||
std::string tga_filename(filename);
|
||||
tga_filename.replace(tga_filename.size() - 3, 3, "tga");
|
||||
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, realW, realH);
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
|
@ -278,7 +279,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if (false == isDynamic || g_ActiveConfig.bCopyEFBToTexture)
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
if (s_TempFramebuffer == 0)
|
||||
glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
|
@ -294,7 +295,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
|
||||
|
||||
glViewport(0, 0, virtualW, virtualH);
|
||||
glViewport(0, 0, virtual_width, virtual_height);
|
||||
|
||||
PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
|
||||
PixelShaderManager::SetColorMatrix(colmat); // set transformation
|
||||
|
@ -317,7 +318,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
|
||||
if (false == g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
hash = TextureConverter::EncodeToRamFromTexture(
|
||||
int encoded_size = TextureConverter::EncodeToRamFromTexture(
|
||||
addr,
|
||||
read_texture,
|
||||
srcFormat == PIXELFMT_Z24,
|
||||
|
@ -325,6 +326,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
dstFormat,
|
||||
scaleByHalf,
|
||||
srcRect);
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
@ -337,7 +347,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
{
|
||||
static int count = 0;
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, realW, realH);
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -250,78 +250,7 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
|
|||
|
||||
}
|
||||
|
||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
if (bFromZBuffer)
|
||||
{
|
||||
format |= _GX_TF_ZTF;
|
||||
if (copyfmt == 11)
|
||||
format = GX_TF_Z16;
|
||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
||||
format |= _GX_TF_CTF;
|
||||
}
|
||||
else
|
||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
||||
format |= _GX_TF_CTF;
|
||||
|
||||
FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format);
|
||||
if (texconv_shader.glprogid == 0)
|
||||
return;
|
||||
|
||||
u8 *dest_ptr = Memory::GetPointer(address);
|
||||
|
||||
GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source);
|
||||
|
||||
int width = (source.right - source.left) >> bScaleByHalf;
|
||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
||||
|
||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
||||
|
||||
// Invalidate any existing texture covering this memory range.
|
||||
// TODO - don't delete the texture if it already exists, just replace the contents.
|
||||
TextureCache::InvalidateRange(address, size_in_bytes);
|
||||
|
||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
||||
|
||||
// only copy on cache line boundaries
|
||||
// extra pixels are copied but not displayed in the resulting texture
|
||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
||||
|
||||
float sampleStride = bScaleByHalf ? 2.f : 1.f;
|
||||
TextureConversionShader::SetShaderParameters(
|
||||
(float)expandedWidth,
|
||||
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
|
||||
(float)Renderer::EFBToScaledX(source.left),
|
||||
(float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight),
|
||||
Renderer::EFBToScaledXf(sampleStride),
|
||||
Renderer::EFBToScaledYf(sampleStride));
|
||||
|
||||
TargetRectangle scaledSource;
|
||||
scaledSource.top = 0;
|
||||
scaledSource.bottom = expandedHeight;
|
||||
scaledSource.left = 0;
|
||||
scaledSource.right = expandedWidth / samples;
|
||||
int cacheBytes = 32;
|
||||
if ((format & 0x0f) == 6)
|
||||
cacheBytes = 64;
|
||||
|
||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
||||
g_renderer->ResetAPIState();
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
|
@ -379,19 +308,8 @@ u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
|||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource,
|
||||
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
|
||||
true, bScaleByHalf > 0 && !bFromZBuffer);
|
||||
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
|
||||
|
||||
u64 hash = GetHash64(dest_ptr, size_in_bytes,
|
||||
g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
if (g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
{
|
||||
// If the texture in RAM is already in the texture cache,
|
||||
// do not copy it again as it has not changed.
|
||||
if (TextureCache::Find(address, hash))
|
||||
return hash;
|
||||
}
|
||||
|
||||
TextureCache::MakeRangeDynamic(address,size_in_bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue