Merge branch 'master' into wii-network

Conflicts:
	Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp
This commit is contained in:
Matthew Parlane 2013-02-09 20:13:11 +13:00
commit 3d480c088f
89 changed files with 6539 additions and 5834 deletions

View File

@ -466,7 +466,7 @@ else(SDL2_FOUND)
else(SDL_FOUND) else(SDL_FOUND)
# TODO: Use the prebuilt one on Windows # TODO: Use the prebuilt one on Windows
message("Using static SDL from Externals") message("Using static SDL from Externals")
include_directories(Externals/SDL Externals/SDL/include) include_directories(Externals/SDL/SDL Externals/SDL Externals/SDL/include)
add_subdirectory(Externals/SDL) add_subdirectory(Externals/SDL)
endif(SDL_FOUND) endif(SDL_FOUND)
endif(SDL2_FOUND) endif(SDL2_FOUND)

View File

@ -1,8 +1,8 @@
# GSSE8P - Sega Soccer Slam # GSSE8P - Sega Soccer Slam
[Core] Values set here will override the main dolphin settings. [Core] Values set here will override the main dolphin settings.
TLBHack = 0
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues = EmulationIssues = Needs real xfb for the videos to display.
EmulationStateId = 4
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
$Master Code $Master Code
@ -19,3 +19,14 @@ $SubZero Have Tons Of Cash
0423C204 05F5E0FF 0423C204 05F5E0FF
$Volta Have Tons Of Cash $Volta Have Tons Of Cash
0423CEA8 05F5E0FF 0423CEA8 05F5E0FF
[Video]
ProjectionHack = 0
PH_SZNear = 0
PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# GSSJ8P - Sega Soccer Slam
[Core] Values set here will override the main dolphin settings.
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues = Needs real xfb for the videos to display.
EmulationStateId = 4
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# GSSP70 - Sega Soccer Slam
[Core] Values set here will override the main dolphin settings.
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues = Needs real xfb for the videos to display.
EmulationStateId = 4
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# GSSP8P - Sega Soccer Slam
[Core] Values set here will override the main dolphin settings.
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationIssues = Needs real xfb for the videos to display.
EmulationStateId = 4
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# GZPE70 - Zapper
[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 = 4
EmulationIssues = Needs real xfb for the videos to display.
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# GZPP70 - Zapper
[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 = 4
EmulationIssues = Needs real xfb for the videos to display.
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -33,8 +33,7 @@ PH_ExtraParam = 1
[5] [5]
Title = Tales of Symphonia GC Title = Tales of Symphonia GC
PH_ZNear = 0.5 PH_ZNear = 0.0002
PH_ZFar = 1
# --------------------------------------------------- # ---------------------------------------------------

View File

@ -0,0 +1,18 @@
# RH8E4F - Tomb Raider Underworld
[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 = 4
EmulationIssues = Needs real Xfb for the videos to display.
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# RH8JEL - Tomb Raider Underworld
[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 = 4
EmulationIssues = Needs real Xfb for the videos to display.
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -1,9 +1,18 @@
# RH8P4F - Tomb Raider Eight # RH8P4F - Tomb Raider Underworld
[Core] Values set here will override the main dolphin settings. [Core] Values set here will override the main dolphin settings.
[EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set. [EmuState] The Emulation State. 1 is worst, 5 is best, 0 is not set.
EmulationStateId = 4 EmulationStateId = 4
EmulationIssues = EmulationIssues = Needs real Xfb for the videos to display.
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
[Video] [Video]
ProjectionHack = 0 ProjectionHack = 0
PH_SZNear = 0
PH_SZFar = 0
PH_ExtraParam = 0
PH_ZNear =
PH_ZFar =
[Gecko]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,18 @@
# RH8X4F - Tomb Raider Underworld
[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 = 4
EmulationIssues = Needs real Xfb for the videos to display.
[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]
[Video_Settings]
UseXFB = True
UseRealXFB = True

View File

@ -0,0 +1,17 @@
# RS5EC8 - SAMURAI WARRIORS KATANA
[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 = 4
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]
[Video_Hacks]
EFBEmulateFormatChanges = True

View File

@ -0,0 +1,17 @@
# RS5JC8 - Sengoku Musou KATANA
[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 = 4
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]
[Video_Hacks]
EFBEmulateFormatChanges = True

View File

@ -0,0 +1,17 @@
# RS5PC8 - SAMURAI WARRIORS KATANA
[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 = 4
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]
[Video_Hacks]
EFBEmulateFormatChanges = True

View File

@ -7,7 +7,11 @@ CPP_FILE_LIST=$(find $SRCDIR \( -name '*.cpp' -o -name '*.h' -o -name '*.c' \) \
xgettext -d dolphin-emu -s --keyword=_ --keyword=wxTRANSLATE --keyword=SuccessAlertT \ xgettext -d dolphin-emu -s --keyword=_ --keyword=wxTRANSLATE --keyword=SuccessAlertT \
--keyword=PanicAlertT --keyword=PanicYesNoT --keyword=AskYesNoT --keyword=_trans \ --keyword=PanicAlertT --keyword=PanicYesNoT --keyword=AskYesNoT --keyword=_trans \
--keyword=CriticalAlertT --add-comments=i18n -p ./Languages/po -o dolphin-emu.pot \ --keyword=CriticalAlertT --add-comments=i18n -p ./Languages/po -o dolphin-emu.pot \
$CPP_FILE_LIST --package-name="Dolphin Emu" $CPP_FILE_LIST --package-name="Dolphin Emulator"
sed -i "s/SOME DESCRIPTIVE TITLE\./Translation of dolphin-emu.pot to LANGUAGE/" Languages/po/dolphin-emu.pot
sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2003-2013/" Languages/po/dolphin-emu.pot
sed -i "s/license as the PACKAGE package/license as the dolphin-emu package/" Languages/po/dolphin-emu.pot
POTFILE=./Languages/po/dolphin-emu.pot POTFILE=./Languages/po/dolphin-emu.pot
PO_FILES=$(find ./Languages/po -name '*.po') PO_FILES=$(find ./Languages/po -name '*.po')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -64,6 +64,8 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC
#include "../HW/WII_IPC.h" #include "../HW/WII_IPC.h"
#include "../Debugger/Debugger_SymbolMap.h" #include "../Debugger/Debugger_SymbolMap.h"
#include "../PowerPC/PowerPC.h" #include "../PowerPC/PowerPC.h"
#include "../HW/SystemTimers.h"
#include "CoreTiming.h"
namespace WII_IPC_HLE_Interface namespace WII_IPC_HLE_Interface
@ -87,8 +89,20 @@ static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc static ipc_msg_queue reply_queue; // arm -> ppc
static std::mutex s_reply_queue; static std::mutex s_reply_queue;
static int enque_reply;
static u64 last_reply_time;
void EnqueReplyCallback(u64 userdata, int)
{
std::lock_guard<std::mutex> lk(s_reply_queue);
reply_queue.push_back(userdata);
}
void Init() void Init()
{ {
enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init"); _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init");
CWII_IPC_HLE_Device_es::m_ContentFile = ""; CWII_IPC_HLE_Device_es::m_ContentFile = "";
u32 i; u32 i;
@ -170,6 +184,7 @@ void Reset(bool _bHard)
std::lock_guard<std::mutex> lk(s_reply_queue); std::lock_guard<std::mutex> lk(s_reply_queue);
reply_queue.clear(); reply_queue.clear();
} }
last_reply_time = 0;
} }
void Shutdown() void Shutdown()
@ -255,6 +270,7 @@ void DoState(PointerWrap &p)
p.Do(request_queue); p.Do(request_queue);
p.Do(reply_queue); p.Do(reply_queue);
p.Do(last_reply_time);
TDeviceMap::const_iterator itr; TDeviceMap::const_iterator itr;
@ -402,18 +418,19 @@ void ExecuteCommand(u32 _Address)
} }
else else
{ {
IWII_IPC_HLE_Device* _pDevice = CreateFileIO(DeviceID, DeviceName); pDevice = CreateFileIO(DeviceID, DeviceName);
CmdSuccess = _pDevice->Open(_Address, Mode); CmdSuccess = pDevice->Open(_Address, Mode);
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
_pDevice->GetDeviceName().c_str(), DeviceID, Mode); pDevice->GetDeviceName().c_str(), DeviceID, Mode);
if (Memory::Read_U32(_Address + 4) == (u32)DeviceID) if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
{ {
g_FdMap[DeviceID] = _pDevice; g_FdMap[DeviceID] = pDevice;
} }
else else
{ {
delete _pDevice; delete pDevice;
pDevice = NULL;
} }
} }
@ -444,7 +461,10 @@ void ExecuteCommand(u32 _Address)
// Don't delete hardware // Don't delete hardware
if (!pDevice->IsHardware()) if (!pDevice->IsHardware())
{
delete pDevice; delete pDevice;
pDevice = NULL;
}
} }
else else
{ {
@ -523,8 +543,19 @@ void ExecuteCommand(u32 _Address)
// IOS seems to write back the command that was responded to // IOS seems to write back the command that was responded to
Memory::Write_U32(Command, _Address + 8); Memory::Write_U32(Command, _Address + 8);
// Ensure replies happen in order, fairly ugly
// Without this, tons of games fail now that DI commads have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();
if (ticks_til_last_reply > 0)
reply_delay = ticks_til_last_reply;
last_reply_time = CoreTiming::GetTicks() + reply_delay;
// Generate a reply to the IPC command // Generate a reply to the IPC command
EnqReply(_Address); EnqReply(_Address, reply_delay);
} }
else else
{ {
@ -546,10 +577,9 @@ void EnqRequest(u32 _Address)
} }
// Called when IOS module has some reply // Called when IOS module has some reply
void EnqReply(u32 _Address) void EnqReply(u32 _Address, int cycles_in_future)
{ {
std::lock_guard<std::mutex> lk(s_reply_queue); CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
reply_queue.push_back(_Address);
} }
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp // This is called every IPC_HLE_PERIOD from SystemTimers.cpp

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include "VolumeCreator.h" #include "VolumeCreator.h"
#include "Filesystem.h" #include "Filesystem.h"
#include "LogManager.h" #include "LogManager.h"
#include "../HW/SystemTimers.h"
#include "../../DiscIO/Src/FileMonitor.h" #include "../../DiscIO/Src/FileMonitor.h"
@ -460,3 +461,44 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
// i dunno but prolly 1 is okay all the time :) // i dunno but prolly 1 is okay all the time :)
return 1; return 1;
} }
int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
{
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
u32 Command = Memory::Read_U32(BufferIn) >> 24;
// Hacks below
switch (Command)
{
case DVDLowRead:
case DVDLowUnencryptedRead:
{
u32 const Size = Memory::Read_U32(BufferIn + 0x04);
// Delay depends on size of read, that makes sense, right?
// More than ~1150K "bytes / sec" hangs NSMBWii on boot.
// Less than ~800K "bytes / sec" hangs DKCR randomly.
return SystemTimers::GetTicksPerSecond() / 975000 * Size;
break;
}
case DVDLowClearCoverInterrupt:
// Less than ~1/155th of a second hangs Oregon Trail at "loading wheel".
// More than ~1/140th of a second hangs Resident Evil Archives: Resident Evil Zero.
return SystemTimers::GetTicksPerSecond() / 146;
break;
// case DVDLowAudioBufferConfig:
// case DVDLowInquiry:
// case DVDLowReadDiskID:
// case DVDLowWaitForCoverClose:
// case DVDLowGetCoverReg:
// case DVDLowGetCoverStatus:
// case DVDLowReset:
// case DVDLowClosePartition:
default:
// ranom numbers here!
return SystemTimers::GetTicksPerSecond() / 1500;
break;
}
}

View File

@ -39,6 +39,8 @@ public:
bool IOCtl(u32 _CommandAddress); bool IOCtl(u32 _CommandAddress);
bool IOCtlV(u32 _CommandAddress); bool IOCtlV(u32 _CommandAddress);
int GetCmdDelay(u32);
private: private:
u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, u32 _BufferOut, u32 BufferOutSize); u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, u32 _BufferOut, u32 BufferOutSize);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -137,6 +137,7 @@
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>
@ -151,6 +152,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>
@ -167,6 +169,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>
@ -181,6 +184,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win32\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>
@ -197,6 +201,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>
@ -213,6 +218,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /
<Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d <Command>xcopy "$(SolutionDir)..\Data" "$(TargetDir)" /e /s /y /d
echo Copying External .dlls echo Copying External .dlls
xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\Cg64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\OpenAL\Win64\*.dll" "$(TargetDir)" /e /s /y /q /d
xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e /s /y /q /d
</Command> </Command>
<Message>Copying Data\* to $(TargetDir)</Message> <Message>Copying Data\* to $(TargetDir)</Message>

View File

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

View File

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

View File

@ -328,8 +328,6 @@ void CISOProperties::CreateGUIControls(bool IsWad)
// Wii Console // Wii Console
EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator); EnableWideScreen = new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DisableWiimoteSpeaker = new wxCheckBox(m_GameConfig, ID_DISABLEWIIMOTESPEAKER, _("Alternate Wiimote Timing"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
DisableWiimoteSpeaker->SetToolTip(_("Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes."));
// Video // Video
UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER); UseBBox = new wxCheckBox(m_GameConfig, ID_USE_BBOX, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
@ -377,10 +375,8 @@ void CISOProperties::CreateGUIControls(bool IsWad)
{ {
sbWiiOverrides->ShowItems(false); sbWiiOverrides->ShowItems(false);
EnableWideScreen->Hide(); EnableWideScreen->Hide();
DisableWiimoteSpeaker->Hide();
} }
sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5); sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5);
sbWiiOverrides->Add(DisableWiimoteSpeaker, 0, wxLEFT, 5);
wxStaticBoxSizer * const sbVideoOverrides = wxStaticBoxSizer * const sbVideoOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video")); new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video"));
@ -966,11 +962,6 @@ void CISOProperties::LoadGameConfig()
else else
EnableWideScreen->Set3StateValue(wxCHK_UNDETERMINED); EnableWideScreen->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Wii", "DisableWiimoteSpeaker", &bTemp))
DisableWiimoteSpeaker->Set3StateValue((wxCheckBoxState)bTemp);
else
DisableWiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "UseBBox", &bTemp)) if (GameIni.Get("Video", "UseBBox", &bTemp))
UseBBox->Set3StateValue((wxCheckBoxState)bTemp); UseBBox->Set3StateValue((wxCheckBoxState)bTemp);
else else
@ -1059,11 +1050,6 @@ bool CISOProperties::SaveGameConfig()
else else
GameIni.Set("Wii", "Widescreen", EnableWideScreen->Get3StateValue()); GameIni.Set("Wii", "Widescreen", EnableWideScreen->Get3StateValue());
if (DisableWiimoteSpeaker->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "DisableWiimoteSpeaker");
else
GameIni.Set("Wii", "DisableWiimoteSpeaker", DisableWiimoteSpeaker->Get3StateValue());
if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED) if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "UseBBox"); GameIni.DeleteKey("Video", "UseBBox");
else else

View File

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

View File

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

View File

@ -18,6 +18,15 @@ namespace ciface
namespace SDL namespace SDL
{ {
std::string GetJoystickName(int index)
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
return SDL_JoystickNameForIndex(index);
#else
return SDL_JoystickName(index);
#endif
}
void Init( std::vector<ControllerInterface::Device*>& devices ) void Init( std::vector<ControllerInterface::Device*>& devices )
{ {
// this is used to number the joysticks // this is used to number the joysticks
@ -32,7 +41,7 @@ void Init( std::vector<ControllerInterface::Device*>& devices )
SDL_Joystick* dev = SDL_JoystickOpen(i); SDL_Joystick* dev = SDL_JoystickOpen(i);
if (dev) if (dev)
{ {
Joystick* js = new Joystick(dev, i, name_counts[SDL_JoystickName(i)]++); Joystick* js = new Joystick(dev, i, name_counts[GetJoystickName(i)]++);
// only add if it has some inputs/outputs // only add if it has some inputs/outputs
if (js->Inputs().size() || js->Outputs().size()) if (js->Inputs().size() || js->Outputs().size())
devices.push_back( js ); devices.push_back( js );
@ -325,7 +334,7 @@ bool Joystick::UpdateOutput()
std::string Joystick::GetName() const std::string Joystick::GetName() const
{ {
return StripSpaces(SDL_JoystickName(m_sdl_index)); return StripSpaces(GetJoystickName(m_sdl_index));
} }
std::string Joystick::GetSource() const std::string Joystick::GetSource() const

View File

@ -5,22 +5,14 @@
#include <list> #include <list>
#ifdef _WIN32
#include <SDL.h> #include <SDL.h>
#else
#include <SDL/SDL.h>
#endif
#if SDL_VERSION_ATLEAST(1, 3, 0) #if SDL_VERSION_ATLEAST(1, 3, 0)
#define USE_SDL_HAPTIC #define USE_SDL_HAPTIC
#endif #endif
#ifdef USE_SDL_HAPTIC #ifdef USE_SDL_HAPTIC
#ifdef _WIN32
#include <SDL_haptic.h> #include <SDL_haptic.h>
#else
#include <SDL/SDL_haptic.h>
#endif
#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC #define SDL_INIT_FLAGS SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC
#else #else
#define SDL_INIT_FLAGS SDL_INIT_JOYSTICK #define SDL_INIT_FLAGS SDL_INIT_JOYSTICK

View File

@ -456,6 +456,7 @@ void BPWritten(const BPCmd& bp)
case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel g_renderer->SetColorMask(); // alpha writing needs to be disabled if the new pixel format doesn't have an alpha channel
g_renderer->SetBlendMode(true);
OnPixelFormatChange(); OnPixelFormatChange();
break; break;

View File

@ -218,6 +218,9 @@ void TextureCache::ClearRenderTargets()
bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels) bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels)
{ {
if (levels == 1)
return false;
// Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black // Just checking if the necessary files exist, if they can't be loaded or have incorrect dimensions LODs will be black
char texBasePathTemp[MAX_PATH]; char texBasePathTemp[MAX_PATH];
char texPathTemp[MAX_PATH]; char texPathTemp[MAX_PATH];
@ -300,7 +303,7 @@ void TextureCache::DumpTexture(TCacheEntryBase* entry, unsigned int level)
TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
u32 address, unsigned int width, unsigned int height, int texformat, u32 address, unsigned int width, unsigned int height, int texformat,
unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem) unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem)
{ {
if (0 == address) if (0 == address)
return NULL; return NULL;
@ -372,7 +375,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// 2. b) For normal textures, all texture parameters need to match // 2. b) For normal textures, all texture parameters need to match
if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format && if (address == entry->addr && tex_hash == entry->hash && full_format == entry->format &&
entry->num_mipmaps == maxlevel && entry->native_width == nativeW && entry->native_height == nativeH) entry->num_mipmaps > maxlevel && entry->native_width == nativeW && entry->native_height == nativeH)
{ {
goto return_entry; goto return_entry;
} }
@ -382,7 +385,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// //
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies? // 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... // TODO: Actually, it should be enough if the internal texture format matches...
if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps == maxlevel) if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps > maxlevel)
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height)) || (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
{ {
// reuse the texture // reuse the texture
@ -428,15 +431,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
} }
} }
// TODO: Cleanup. Plus, we still autogenerate mipmaps in certain cases (we shouldn't do that)
bool isPow2;
unsigned int texLevels; unsigned int texLevels;
isPow2 = !((width & (width - 1)) || (height & (height - 1))); bool use_native_mips;
texLevels = (isPow2 && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2; texLevels = use_mipmaps ? (maxlevel + 1) : 1;
texLevels = maxlevel ? std::min(texLevels, maxlevel + 1) : texLevels;
using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels); using_custom_lods = using_custom_texture && CheckForCustomTextureLODs(tex_hash, texformat, texLevels);
UseNativeMips = UseNativeMips && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
texLevels = (UseNativeMips || using_custom_lods) ? texLevels : !isPow2; texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1;
// create the entry/texture // create the entry/texture
if (NULL == entry) { if (NULL == entry) {
@ -445,9 +445,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// Sometimes, we can get around recreating a texture if only the number of mip levels 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 // 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 // Thus, we don't update this member for every Load, but just whenever the texture gets recreated
// // TODO: D3D9 doesn't support min_lod. We should add a workaround for that here!
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels? entry->num_mipmaps = maxlevel + 1;
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
entry->type = TCET_NORMAL; entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
@ -460,13 +459,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
else entry->type = TCET_NORMAL; else entry->type = TCET_NORMAL;
// load texture // load texture
entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); entry->Load(width, height, expandedWidth, 0);
if (g_ActiveConfig.bDumpTextures && !using_custom_texture) if (g_ActiveConfig.bDumpTextures && !using_custom_texture)
DumpTexture(entry, 0); DumpTexture(entry, 0);
// load mips - TODO: Loading mipmaps from tmem is untested! // load mips - TODO: Loading mipmaps from tmem is untested!
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && UseNativeMips) if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE && use_native_mips)
{ {
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat); const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
@ -495,7 +494,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
expandedHeight = (currentHeight + bsh) & (~bsh); expandedHeight = (currentHeight + bsh) & (~bsh);
TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
entry->Load(currentWidth, currentHeight, expandedWidth, level, false); entry->Load(currentWidth, currentHeight, expandedWidth, level);
if (g_ActiveConfig.bDumpTextures) if (g_ActiveConfig.bDumpTextures)
DumpTexture(entry, level); DumpTexture(entry, level);
@ -518,7 +517,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight); LoadCustomTexture(tex_hash, texformat, level, currentWidth, currentHeight);
entry->Load(currentWidth, currentHeight, currentWidth, level, false); entry->Load(currentWidth, currentHeight, currentWidth, level);
mipWidth >>= 1; mipWidth >>= 1;
mipHeight >>= 1; mipHeight >>= 1;

View File

@ -89,7 +89,7 @@ public:
virtual bool Save(const char filename[], unsigned int level) = 0; virtual bool Save(const char filename[], unsigned int level) = 0;
virtual void Load(unsigned int width, unsigned int height, virtual void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0; unsigned int expanded_width, unsigned int level) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid, bool isIntensity, bool scaleByHalf, unsigned int cbufid,
@ -116,7 +116,7 @@ public:
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0; 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, static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem); int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat, static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf); const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);

View File

@ -54,8 +54,6 @@ static int s_fps = 0;
static u32 s_LastAA = 0; static u32 s_LastAA = 0;
static u32 s_blendMode;
static Television s_television; static Television s_television;
ID3D11Buffer* access_efb_cbuf = NULL; ID3D11Buffer* access_efb_cbuf = NULL;
@ -76,151 +74,6 @@ struct
D3D11_RASTERIZER_DESC rastdc; D3D11_RASTERIZER_DESC rastdc;
} gx_state; } gx_state;
// State translation lookup tables
static const D3D11_BLEND d3dSrcFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_DEST_COLOR,
D3D11_BLEND_INV_DEST_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
static const D3D11_BLEND d3dDestFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_SRC_COLOR,
D3D11_BLEND_INV_SRC_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
static const D3D11_BLEND_OP d3dLogicOps[16] =
{
D3D11_BLEND_OP_ADD,//0
D3D11_BLEND_OP_ADD,//1
D3D11_BLEND_OP_SUBTRACT,//2
D3D11_BLEND_OP_ADD,//3
D3D11_BLEND_OP_REV_SUBTRACT,//4
D3D11_BLEND_OP_ADD,//5
D3D11_BLEND_OP_MAX,//6
D3D11_BLEND_OP_ADD,//7
D3D11_BLEND_OP_MAX,//8
D3D11_BLEND_OP_MAX,//9
D3D11_BLEND_OP_ADD,//10
D3D11_BLEND_OP_ADD,//11
D3D11_BLEND_OP_ADD,//12
D3D11_BLEND_OP_ADD,//13
D3D11_BLEND_OP_ADD,//14
D3D11_BLEND_OP_ADD//15
};
static const D3D11_BLEND d3dLogicOpSrcFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_DEST_COLOR,//1
D3D11_BLEND_ONE,//2
D3D11_BLEND_ONE,//3
D3D11_BLEND_DEST_COLOR,//4
D3D11_BLEND_ZERO,//5
D3D11_BLEND_INV_DEST_COLOR,//6
D3D11_BLEND_INV_DEST_COLOR,//7
D3D11_BLEND_INV_SRC_COLOR,//8
D3D11_BLEND_INV_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_ONE,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_INV_SRC_COLOR,//13
D3D11_BLEND_INV_DEST_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_BLEND d3dLogicOpDestFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_ZERO,//1
D3D11_BLEND_INV_SRC_COLOR,//2
D3D11_BLEND_ZERO,//3
D3D11_BLEND_ONE,//4
D3D11_BLEND_ONE,//5
D3D11_BLEND_INV_SRC_COLOR,//6
D3D11_BLEND_ONE,//7
D3D11_BLEND_INV_DEST_COLOR,//8
D3D11_BLEND_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_INV_DEST_COLOR,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_ONE,//13
D3D11_BLEND_INV_SRC_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_CULL_MODE d3dCullModes[4] =
{
D3D11_CULL_NONE,
D3D11_CULL_BACK,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
};
static const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_ALWAYS
};
#define TEXF_NONE 0
#define TEXF_POINT 1
#define TEXF_LINEAR 2
static const unsigned int d3dMipFilters[4] =
{
TEXF_NONE,
TEXF_POINT,
TEXF_LINEAR,
TEXF_NONE, //reserved
};
static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
void SetupDeviceObjects() void SetupDeviceObjects()
{ {
@ -338,7 +191,6 @@ void CreateScreenshotTexture()
Renderer::Renderer() Renderer::Renderer()
{ {
int x, y, w_temp, h_temp; int x, y, w_temp, h_temp;
s_blendMode = 0;
InitFPSCounter(); InitFPSCounter();
@ -833,6 +685,32 @@ void SetBlendOp(D3D11_BLEND_OP val)
void Renderer::SetBlendMode(bool forceUpdate) void Renderer::SetBlendMode(bool forceUpdate)
{ {
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
const D3D11_BLEND d3dSrcFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_DEST_COLOR,
D3D11_BLEND_INV_DEST_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
(target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE,
(target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
const D3D11_BLEND d3dDestFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_SRC_COLOR,
D3D11_BLEND_INV_SRC_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
(target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE,
(target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
if (bpmem.blendmode.logicopenable && !forceUpdate) if (bpmem.blendmode.logicopenable && !forceUpdate)
return; return;
@ -845,8 +723,8 @@ void Renderer::SetBlendMode(bool forceUpdate)
} }
else else
{ {
gx_state.blenddc.RenderTarget[0].BlendEnable = bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)); gx_state.blenddc.RenderTarget[0].BlendEnable = bpmem.blendmode.blendenable;
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))) if (bpmem.blendmode.blendenable)
{ {
SetBlendOp(D3D11_BLEND_OP_ADD); SetBlendOp(D3D11_BLEND_OP_ADD);
SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]); SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]);
@ -1331,12 +1209,32 @@ void Renderer::RestoreCull()
void Renderer::SetGenerationMode() void Renderer::SetGenerationMode()
{ {
const D3D11_CULL_MODE d3dCullModes[4] =
{
D3D11_CULL_NONE,
D3D11_CULL_BACK,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
};
// rastdc.FrontCounterClockwise must be false for this to work // rastdc.FrontCounterClockwise must be false for this to work
gx_state.rastdc.CullMode = d3dCullModes[bpmem.genMode.cullmode]; gx_state.rastdc.CullMode = d3dCullModes[bpmem.genMode.cullmode];
} }
void Renderer::SetDepthMode() void Renderer::SetDepthMode()
{ {
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_ALWAYS
};
if (bpmem.zmode.testenable) if (bpmem.zmode.testenable)
{ {
gx_state.depthdc.DepthEnable = TRUE; gx_state.depthdc.DepthEnable = TRUE;
@ -1353,9 +1251,85 @@ void Renderer::SetDepthMode()
void Renderer::SetLogicOpMode() void Renderer::SetLogicOpMode()
{ {
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) // D3D11 doesn't support logic blending, so this is a huge hack
// TODO: Make use of D3D11.1's logic blending support
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
const D3D11_BLEND_OP d3dLogicOps[16] =
{
D3D11_BLEND_OP_ADD,//0
D3D11_BLEND_OP_ADD,//1
D3D11_BLEND_OP_SUBTRACT,//2
D3D11_BLEND_OP_ADD,//3
D3D11_BLEND_OP_REV_SUBTRACT,//4
D3D11_BLEND_OP_ADD,//5
D3D11_BLEND_OP_MAX,//6
D3D11_BLEND_OP_ADD,//7
D3D11_BLEND_OP_MAX,//8
D3D11_BLEND_OP_MAX,//9
D3D11_BLEND_OP_ADD,//10
D3D11_BLEND_OP_ADD,//11
D3D11_BLEND_OP_ADD,//12
D3D11_BLEND_OP_ADD,//13
D3D11_BLEND_OP_ADD,//14
D3D11_BLEND_OP_ADD//15
};
const D3D11_BLEND d3dLogicOpSrcFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_DEST_COLOR,//1
D3D11_BLEND_ONE,//2
D3D11_BLEND_ONE,//3
D3D11_BLEND_DEST_COLOR,//4
D3D11_BLEND_ZERO,//5
D3D11_BLEND_INV_DEST_COLOR,//6
D3D11_BLEND_INV_DEST_COLOR,//7
D3D11_BLEND_INV_SRC_COLOR,//8
D3D11_BLEND_INV_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_ONE,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_INV_SRC_COLOR,//13
D3D11_BLEND_INV_DEST_COLOR,//14
D3D11_BLEND_ONE//15
};
const D3D11_BLEND d3dLogicOpDestFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_ZERO,//1
D3D11_BLEND_INV_SRC_COLOR,//2
D3D11_BLEND_ZERO,//3
D3D11_BLEND_ONE,//4
D3D11_BLEND_ONE,//5
D3D11_BLEND_INV_SRC_COLOR,//6
D3D11_BLEND_ONE,//7
D3D11_BLEND_INV_DEST_COLOR,//8
D3D11_BLEND_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_INV_DEST_COLOR,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_ONE,//13
D3D11_BLEND_INV_SRC_COLOR,//14
D3D11_BLEND_ONE//15
};
if (bpmem.blendmode.logicopenable)
{ {
s_blendMode = 0;
gx_state.blenddc.RenderTarget[0].BlendEnable = true; gx_state.blenddc.RenderTarget[0].BlendEnable = true;
SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]); SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]);
SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]); SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]);
@ -1379,18 +1353,32 @@ void Renderer::SetLineWidth()
void Renderer::SetSamplerState(int stage, int texindex) void Renderer::SetSamplerState(int stage, int texindex)
{ {
#define TEXF_NONE 0
#define TEXF_POINT 1
#define TEXF_LINEAR 2
const unsigned int d3dMipFilters[4] =
{
TEXF_NONE,
TEXF_POINT,
TEXF_LINEAR,
TEXF_NONE, //reserved
};
const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
const FourTexUnits &tex = bpmem.tex[texindex]; const FourTexUnits &tex = bpmem.tex[texindex];
const TexMode0 &tm0 = tex.texMode0[stage]; const TexMode0 &tm0 = tex.texMode0[stage];
const TexMode1 &tm1 = tex.texMode1[stage]; const TexMode1 &tm1 = tex.texMode1[stage];
unsigned int mip; unsigned int mip = d3dMipFilters[tm0.min_filter & 3];
mip = (tm0.min_filter == 8) ? TEXF_NONE:d3dMipFilters[tm0.min_filter & 3];
if ((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) mip = TEXF_NONE;
if (texindex) stage += 4; if (texindex) stage += 4;
// TODO: Clarify whether these values are correct
// NOTE: since there's no "no filter" in DX11 we're using point filters in these cases
if (g_ActiveConfig.bForceFiltering) if (g_ActiveConfig.bForceFiltering)
{ {
gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
@ -1432,7 +1420,7 @@ void Renderer::SetSamplerState(int stage, int texindex)
// When mipfilter is set to "none", just disable mipmapping altogether // When mipfilter is set to "none", just disable mipmapping altogether
gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f; gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f;
gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f; gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f;
gx_state.sampdc[stage].MipLODBias = (float)tm0.lod_bias/32.0f; gx_state.sampdc[stage].MipLODBias = (s32)tm0.lod_bias/32.0f;
} }
void Renderer::SetInterlacingMode() void Renderer::SetInterlacingMode()

View File

@ -59,12 +59,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage); D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
if (autogen_mips)
PD3DX11FilterTexture(D3D::context, texture->GetTex(), 0, D3DX11_DEFAULT);
} }
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,

View File

@ -41,7 +41,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false); unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -237,8 +237,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)

View File

@ -73,148 +73,6 @@ static char *st;
static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL; static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL;
// State translation lookup tables
static const D3DBLEND d3dSrcFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
static const D3DBLEND d3dDestFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
static const D3DBLENDOP d3dLogicOpop[16] =
{
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_SUBTRACT,
D3DBLENDOP_ADD,
D3DBLENDOP_REVSUBTRACT,
D3DBLENDOP_ADD,
D3DBLENDOP_MAX,
D3DBLENDOP_ADD,
D3DBLENDOP_MAX,
D3DBLENDOP_MAX,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD
};
static const D3DBLEND d3dLogicOpSrcFactors[16] =
{
D3DBLEND_ZERO,
D3DBLEND_DESTCOLOR,
D3DBLEND_ONE,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_ZERO,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_ONE
};
static const D3DBLEND d3dLogicOpDestFactors[16] =
{
D3DBLEND_ZERO,
D3DBLEND_ZERO,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE
};
static const D3DCULL d3dCullModes[4] =
{
D3DCULL_NONE,
D3DCULL_CCW,
D3DCULL_CW,
D3DCULL_CCW
};
static const D3DCMPFUNC d3dCmpFuncs[8] =
{
D3DCMP_NEVER,
D3DCMP_LESS,
D3DCMP_EQUAL,
D3DCMP_LESSEQUAL,
D3DCMP_GREATER,
D3DCMP_NOTEQUAL,
D3DCMP_GREATEREQUAL,
D3DCMP_ALWAYS
};
static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
{
D3DTEXF_NONE,
D3DTEXF_POINT,
D3DTEXF_LINEAR,
D3DTEXF_NONE, //reserved
};
static const D3DTEXTUREADDRESS d3dClamps[4] =
{
D3DTADDRESS_CLAMP,
D3DTADDRESS_WRAP,
D3DTADDRESS_MIRROR,
D3DTADDRESS_WRAP //reserved
};
void SetupDeviceObjects() void SetupDeviceObjects()
{ {
D3D::font.Init(); D3D::font.Init();
@ -796,6 +654,32 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
void Renderer::SetBlendMode(bool forceUpdate) void Renderer::SetBlendMode(bool forceUpdate)
{ {
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
const D3DBLEND d3dSrcFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
(target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE,
(target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
const D3DBLEND d3dDestFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
(target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE,
(target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
if (bpmem.blendmode.logicopenable && !forceUpdate) if (bpmem.blendmode.logicopenable && !forceUpdate)
return; return;
@ -808,8 +692,8 @@ void Renderer::SetBlendMode(bool forceUpdate)
} }
else else
{ {
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))); D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable);
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))) if (bpmem.blendmode.blendenable)
{ {
D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]); D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]);
@ -1261,11 +1145,31 @@ void Renderer::RestoreAPIState()
void Renderer::SetGenerationMode() void Renderer::SetGenerationMode()
{ {
const D3DCULL d3dCullModes[4] =
{
D3DCULL_NONE,
D3DCULL_CCW,
D3DCULL_CW,
D3DCULL_CCW
};
D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
} }
void Renderer::SetDepthMode() void Renderer::SetDepthMode()
{ {
const D3DCMPFUNC d3dCmpFuncs[8] =
{
D3DCMP_NEVER,
D3DCMP_LESS,
D3DCMP_EQUAL,
D3DCMP_LESSEQUAL,
D3DCMP_GREATER,
D3DCMP_NOTEQUAL,
D3DCMP_GREATEREQUAL,
D3DCMP_ALWAYS
};
if (bpmem.zmode.testenable) if (bpmem.zmode.testenable)
{ {
D3D::SetRenderState(D3DRS_ZENABLE, TRUE); D3D::SetRenderState(D3DRS_ZENABLE, TRUE);
@ -1282,7 +1186,83 @@ void Renderer::SetDepthMode()
void Renderer::SetLogicOpMode() void Renderer::SetLogicOpMode()
{ {
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) // D3D9 doesn't support logic blending, so this is a huge hack
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
const D3DBLENDOP d3dLogicOpop[16] =
{
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_SUBTRACT,
D3DBLENDOP_ADD,
D3DBLENDOP_REVSUBTRACT,
D3DBLENDOP_ADD,
D3DBLENDOP_MAX,
D3DBLENDOP_ADD,
D3DBLENDOP_MAX,
D3DBLENDOP_MAX,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD,
D3DBLENDOP_ADD
};
const D3DBLEND d3dLogicOpSrcFactors[16] =
{
D3DBLEND_ZERO,
D3DBLEND_DESTCOLOR,
D3DBLEND_ONE,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_ZERO,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_ONE
};
const D3DBLEND d3dLogicOpDestFactors[16] =
{
D3DBLEND_ZERO,
D3DBLEND_ZERO,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_ONE
};
if (bpmem.blendmode.logicopenable)
{ {
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true); D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true);
D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]); D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]);
@ -1310,6 +1290,21 @@ void Renderer::SetLineWidth()
void Renderer::SetSamplerState(int stage, int texindex) void Renderer::SetSamplerState(int stage, int texindex)
{ {
const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
{
D3DTEXF_NONE,
D3DTEXF_POINT,
D3DTEXF_LINEAR,
D3DTEXF_NONE, //reserved
};
const D3DTEXTUREADDRESS d3dClamps[4] =
{
D3DTADDRESS_CLAMP,
D3DTADDRESS_WRAP,
D3DTADDRESS_MIRROR,
D3DTADDRESS_WRAP //reserved
};
const FourTexUnits &tex = bpmem.tex[texindex]; const FourTexUnits &tex = bpmem.tex[texindex];
const TexMode0 &tm0 = tex.texMode0[stage]; const TexMode0 &tm0 = tex.texMode0[stage];
const TexMode1 &tm1 = tex.texMode1[stage]; const TexMode1 &tm1 = tex.texMode1[stage];
@ -1323,9 +1318,7 @@ void Renderer::SetSamplerState(int stage, int texindex)
{ {
min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mip = (tm0.min_filter == 8) ? D3DTEXF_NONE : d3dMipFilters[tm0.min_filter & 3]; mip = d3dMipFilters[tm0.min_filter & 3];
if((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0))
mip = D3DTEXF_NONE;
} }
if (texindex) if (texindex)
stage += 4; stage += 4;
@ -1340,8 +1333,8 @@ void Renderer::SetSamplerState(int stage, int texindex)
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]);
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]);
//float SuperSampleCoeficient = (s_LastAA < 3)? s_LastAA + 1 : s_LastAA - 1;// uncoment this changes to conserve detail when incresing ssaa level
float lodbias = (tm0.lod_bias / 32.0f);// + (s_LastAA)?(log(SuperSampleCoeficient) / log(2.0f)):0; float lodbias = (s32)tm0.lod_bias / 32.0f;
D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias); D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias);
D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4); D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4);
} }

View File

@ -72,10 +72,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level); D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level);
// D3D9 will automatically generate mip maps if necessary
} }
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,

View File

@ -44,7 +44,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false); unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -333,8 +333,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)

View File

@ -132,58 +132,6 @@ const u32 EFB_CACHE_HEIGHT = (EFB_HEIGHT + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_
static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; static bool s_efbCacheValid[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT];
static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2 for PEEK_Z and PEEK_COLOR
static const GLenum glSrcFactors[8] =
{
GL_ZERO,
GL_ONE,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA, // NOTE: If dual-source blending is enabled, use SRC1_ALPHA
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA
};
static const GLenum glDestFactors[8] = {
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA, // NOTE: If dual-source blending is enabled, use SRC1_ALPHA
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA
};
static const GLenum glCmpFuncs[8] = {
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS
};
static const GLenum glLogicOpCodes[16] = {
GL_CLEAR,
GL_AND,
GL_AND_REVERSE,
GL_COPY,
GL_AND_INVERTED,
GL_NOOP,
GL_XOR,
GL_OR,
GL_NOR,
GL_EQUIV,
GL_INVERT,
GL_OR_REVERSE,
GL_COPY_INVERTED,
GL_OR_INVERTED,
GL_NAND,
GL_SET
};
#if defined HAVE_CG && HAVE_CG #if defined HAVE_CG && HAVE_CG
void HandleCgError(CGcontext ctx, CGerror err, void* appdata) void HandleCgError(CGcontext ctx, CGerror err, void* appdata)
@ -908,6 +856,32 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
void Renderer::SetBlendMode(bool forceUpdate) void Renderer::SetBlendMode(bool forceUpdate)
{ {
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
const GLenum glSrcFactors[8] =
{
GL_ZERO,
GL_ONE,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA, // NOTE: If dual-source blending is enabled, use SRC1_ALPHA
(target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE,
(target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO
};
const GLenum glDestFactors[8] =
{
GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA, // NOTE: If dual-source blending is enabled, use SRC1_ALPHA
(target_has_alpha) ? GL_DST_ALPHA : (GLenum)GL_ONE,
(target_has_alpha) ? GL_ONE_MINUS_DST_ALPHA : (GLenum)GL_ZERO
};
// blend mode bit mask // blend mode bit mask
// 0 - blend enable // 0 - blend enable
// 2 - reverse subtract enable (else add) // 2 - reverse subtract enable (else add)
@ -951,10 +925,10 @@ void Renderer::SetBlendMode(bool forceUpdate)
if (changes & 0x1F8) if (changes & 0x1F8)
{ {
#ifdef USE_DUAL_SOURCE_BLEND
GLenum srcFactor = glSrcFactors[(newval >> 3) & 7]; GLenum srcFactor = glSrcFactors[(newval >> 3) & 7];
GLenum srcFactorAlpha = srcFactor;
GLenum dstFactor = glDestFactors[(newval >> 6) & 7]; GLenum dstFactor = glDestFactors[(newval >> 6) & 7];
#ifdef USE_DUAL_SOURCE_BLEND
GLenum srcFactorAlpha = srcFactor;
GLenum dstFactorAlpha = dstFactor; GLenum dstFactorAlpha = dstFactor;
if (useDualSource) if (useDualSource)
{ {
@ -975,7 +949,7 @@ void Renderer::SetBlendMode(bool forceUpdate)
// blend RGB change // blend RGB change
glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha); glBlendFuncSeparate(srcFactor, dstFactor, srcFactorAlpha, dstFactorAlpha);
#else #else
glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); glBlendFunc(srcFactor, dstFactor);
#endif #endif
} }
@ -1438,6 +1412,18 @@ void Renderer::SetGenerationMode()
void Renderer::SetDepthMode() void Renderer::SetDepthMode()
{ {
const GLenum glCmpFuncs[8] =
{
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS
};
if (bpmem.zmode.testenable) if (bpmem.zmode.testenable)
{ {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -1454,7 +1440,27 @@ void Renderer::SetDepthMode()
void Renderer::SetLogicOpMode() void Renderer::SetLogicOpMode()
{ {
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) const GLenum glLogicOpCodes[16] =
{
GL_CLEAR,
GL_AND,
GL_AND_REVERSE,
GL_COPY,
GL_AND_INVERTED,
GL_NOOP,
GL_XOR,
GL_OR,
GL_NOR,
GL_EQUIV,
GL_INVERT,
GL_OR_REVERSE,
GL_COPY_INVERTED,
GL_OR_INVERTED,
GL_NAND,
GL_SET
};
if (bpmem.blendmode.logicopenable)
{ {
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);

View File

@ -58,24 +58,6 @@ namespace OGL
static u32 s_TempFramebuffer = 0; static u32 s_TempFramebuffer = 0;
static const GLint c_MinLinearFilter[8] = {
GL_NEAREST,
GL_NEAREST_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_NEAREST,
GL_LINEAR,
GL_LINEAR_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR,
};
static const GLint c_WrapSettings[4] = {
GL_CLAMP_TO_EDGE,
GL_REPEAT,
GL_MIRRORED_REPEAT,
GL_REPEAT,
};
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level) bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
{ {
int width = std::max(virtual_width >> level, 1); int width = std::max(virtual_width >> level, 1);
@ -201,7 +183,7 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
} }
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips) unsigned int expanded_width, unsigned int level)
{ {
//glEnable(GL_TEXTURE_2D); //glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
@ -212,16 +194,7 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
if (expanded_width != width) if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
if (bHaveMipMaps && autogen_mips)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp); glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
}
else
{
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
}
if (expanded_width != width) if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -357,32 +330,40 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1) void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1)
{ {
// TODO: not used anywhere const GLint c_MinLinearFilter[8] =
TexMode0 mode = newmode;
//mode1 = newmode1;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
(newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
if (bHaveMipMaps)
{ {
// TODO: not used anywhere GL_NEAREST,
if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4) GL_NEAREST_MIPMAP_NEAREST,
mode.min_filter += 4; // take equivalent forced linear GL_NEAREST_MIPMAP_LINEAR,
GL_NEAREST,
GL_LINEAR,
GL_LINEAR_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR,
};
const GLint c_WrapSettings[4] =
{
GL_CLAMP_TO_EDGE,
GL_REPEAT,
GL_MIRRORED_REPEAT,
GL_REPEAT,
};
int filt = newmode.min_filter; int filt = newmode.min_filter;
if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4)
filt += 4; // take equivalent forced linear
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod >> 4); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod >> 4);
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias / 32.0f)); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod / 16.f);
} glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod / 16.f);
else glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (s32)newmode.lod_bias / 32.0f);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
(g_ActiveConfig.bForceFiltering || newmode.min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]);
// TODO: Reset anisotrop when changed to 1
if (g_Config.iMaxAnisotropy >= 1) if (g_Config.iMaxAnisotropy >= 1)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
(float)(1 << g_ActiveConfig.iMaxAnisotropy)); (float)(1 << g_ActiveConfig.iMaxAnisotropy));

View File

@ -54,7 +54,7 @@ private:
~TCacheEntry(); ~TCacheEntry();
void Load(unsigned int width, unsigned int height, void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips = false); unsigned int expanded_width, unsigned int level);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat, void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, unsigned int srcFormat, const EFBRectangle& srcRect,

View File

@ -164,8 +164,8 @@ void VertexManager::vFlush()
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format, tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8), (tex.texMode0[i&3].min_filter & 3),
tex.texMode1[i&3].max_lod >> 4, ceil(tex.texMode1[i&3].max_lod / 16.f),
tex.texImage1[i&3].image_type); tex.texImage1[i&3].image_type);
if (tentry) if (tentry)

View File

@ -431,7 +431,7 @@ static bool AlphaCompare(int alpha, int ref, int comp)
return true; return true;
} }
static bool AlphaTest(int alpha) static bool TevAlphaTest(int alpha)
{ {
bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0); bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0);
bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1); bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1);
@ -700,7 +700,7 @@ void Tev::Draw()
// convert to 8 bits per component // convert to 8 bits per component
u8 output[4] = {(u8)Reg[0][ALP_C], (u8)Reg[0][BLU_C], (u8)Reg[0][GRN_C], (u8)Reg[0][RED_C]}; u8 output[4] = {(u8)Reg[0][ALP_C], (u8)Reg[0][BLU_C], (u8)Reg[0][GRN_C], (u8)Reg[0][RED_C]};
if (!AlphaTest(output[ALP_C])) if (!TevAlphaTest(output[ALP_C]))
return; return;
// z texture // z texture