Merge pull request #814 from LukeUsher/avmode-fixes

Properly implement D3DDevice_GetDisplayFieldStatus patch
This commit is contained in:
PatrickvL 2017-11-30 14:18:33 +01:00 committed by GitHub
commit edae7898f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 22 deletions

View File

@ -121,18 +121,29 @@ xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
// TODO : Verify checksums
// Check for (and fix) invalid fields that were set by previous versions of Cxbx-Reloaded
// Without this, all users would have to delete their EEPROM.bin
// The issue was that the AV_FLAG_XXhz was set in the wrong field, we fix it by
// resetting FactorySettings.AVRegion and setting user video flags to the default
// The user can then set their desired settings using the Xbox Dashboard
if (pEEPROM->FactorySettings.AVRegion == AV_STANDARD_NTSC_M) {
DbgPrintf("INIT: Repairing bad EEPROM (from previous Cxbx-Reloaded builds)\n");
pEEPROM->UserSettings.VideoFlags = 0;
pEEPROM->FactorySettings.AVRegion = AV_STANDARD_NTSC_M | AV_FLAGS_60Hz;
}
if (NeedsInitialization)
{
memset(pEEPROM, 0, EEPROM_SIZE);
// TODO: Make these configurable or autodetect of some sort :
pEEPROM->UserSettings.Language = 0x01; // = English
pEEPROM->UserSettings.VideoFlags = (AV_FLAGS_LETTERBOX | AV_FLAGS_60Hz) >> AV_USER_FLAGS_SHIFT; // = Letterbox
pEEPROM->UserSettings.AudioFlags = 0; // = Stereo, no AC3, no DTS
pEEPROM->UserSettings.VideoFlags = 0; // = Use XDK defaults
pEEPROM->UserSettings.AudioFlags = 0; // = Stereo, no AC3, no DTS
pEEPROM->UserSettings.ParentalControlGames = 0; // = XC_PC_ESRB_ALL
pEEPROM->UserSettings.ParentalControlMovies = 0; // = XC_PC_ESRB_ALL
pEEPROM->UserSettings.MiscFlags = 0; // No automatic power down
pEEPROM->FactorySettings.AVRegion = AV_STANDARD_NTSC_M; // = 0x100 = NTSC_M
pEEPROM->FactorySettings.AVRegion = AV_STANDARD_NTSC_M | AV_FLAGS_60Hz;
XboxFactoryGameRegion = 1; // = North America - TODO : This should be derived from EncryptedSection somehow

View File

@ -2494,18 +2494,38 @@ HRESULT WINAPI XTL::EMUPATCH(D3D_CheckDeviceFormat)
// ******************************************************************
VOID WINAPI XTL::EMUPATCH(D3DDevice_GetDisplayFieldStatus)(X_D3DFIELD_STATUS *pFieldStatus)
{
//FUNC_EXPORTS
// NOTE: This can be unpatched only when NV2A does it's own VBlank and HLE _Swap function is unpatched
FUNC_EXPORTS
LOG_FUNC_ONE_ARG(pFieldStatus);
// TODO: Read AV Flags to determine if Progressive or Interlaced
#if 1
pFieldStatus->Field = (g_VBData.VBlank%2 == 0) ? X_D3DFIELD_ODD : X_D3DFIELD_EVEN;
pFieldStatus->VBlankCount = g_VBData.VBlank;
#else
pFieldStatus->Field = X_D3DFIELD_PROGRESSIVE;
pFieldStatus->VBlankCount = 0;
#endif
// Read AV Flags to determine if Progressive or Interlaced
// The xbox does this by reading from pDevice->m_Miniport.m_CurrentAvInfo
// but we don't have an OOVPA for that. Instead, we call the Xbox implementation of
// D3DDevice_GetDisplayMode and read the result
// Get a function pointer to the unpatched xbox function D3DDevice_GetDisplayMode
typedef VOID(__stdcall *XB_D3DDevice_GetDisplayMode_t)(X_D3DDISPLAYMODE*);
static XB_D3DDevice_GetDisplayMode_t XB_D3DDevice_GetDisplayMode = (XB_D3DDevice_GetDisplayMode_t)GetXboxFunctionPointer("D3DDevice_GetDisplayMode");
// Check the function pointer for validity, if it is not valid, we must abort as we have a missing OOVPA
if (XB_D3DDevice_GetDisplayMode == nullptr) {
CxbxKrnlCleanup("D3DDevice_GetDisplayFieldStatus: Could not locate D3DDevice_GetDisplayMode");
}
// Call the Xbox GetDisplayMode function to retrieve flags for the active video mode
X_D3DDISPLAYMODE displayMode;
XB_D3DDevice_GetDisplayMode(&displayMode);
// Set the VBlank count
pFieldStatus->VBlankCount = g_VBData.VBlank;
// If we are interlaced, return the current field, otherwise, return progressive scan
if (displayMode.Flags & X_D3DPRESENTFLAG_INTERLACED) {
pFieldStatus->Field = (g_VBData.VBlank % 2 == 0) ? X_D3DFIELD_ODD : X_D3DFIELD_EVEN;
} else {
pFieldStatus->Field = X_D3DFIELD_PROGRESSIVE;
}
}
// ******************************************************************

View File

@ -260,6 +260,8 @@ typedef enum _X_D3DSET_DEPTH_CLIP_PLANES_FLAGS
}
X_D3DSET_DEPTH_CLIP_PLANES_FLAGS;
#define X_D3DPRESENTFLAG_INTERLACED 0x00000020
typedef struct _X_D3DDISPLAYMODE
{
UINT Width;

View File

@ -63,16 +63,40 @@ PVOID g_pPersistedData = NULL;
ULONG AvQueryAvCapabilities()
{
// This is the only AV mode we currently emulate, so we can hardcode the return value
// TODO: Once we allow the user to configure the connected AV pack, we should implement this proper
// This function should first query the AV Pack type, read the user's EEPROM settings and
// return the correct flags based on this.
//
// For the AV Pack, read SMC_COMMAND_VIDEO_MODE (or HalBootSMCVideoMode) and convert it to a AV_PACK_*
//
// To read the EEPROM, call ExQueryNonVolatileSetting() with these config flags :
// XC_FACTORY_AV_REGION; if that fails, fallback on AV_STANDARD_NTSC_M | AV_FLAGS_60Hz
// XC_VIDEO_FLAGS; if that fails, fallback on 0
return AV_PACK_HDTV | AV_STANDARD_NTSC_M | AV_FLAGS_60Hz;
// TODO: Once we add the ability to change av pack, read HalSmcVideoMode) and convert it to a AV_PACK_*
ULONG avpack = AV_PACK_HDTV;
ULONG type;
ULONG resultSize;
// First, read the factory AV settings
ULONG avRegion;
NTSTATUS result = xboxkrnl::ExQueryNonVolatileSetting(
xboxkrnl::XC_FACTORY_AV_REGION,
&type,
&avRegion,
sizeof(ULONG),
&resultSize);
// If this failed, default to AV_STANDARD_NTSC_M | AV_FLAGS_60Hz
if (result != STATUS_SUCCESS || resultSize != sizeof(ULONG)) {
avRegion = AV_STANDARD_NTSC_M | AV_FLAGS_60Hz;
}
// Read the user-configurable (via the dashboard) settings
ULONG userSettings;
result = xboxkrnl::ExQueryNonVolatileSetting(
xboxkrnl::XC_VIDEO,
&type,
&userSettings,
sizeof(ULONG),
&resultSize);
// If this failed, default to no user-options set
if (result != STATUS_SUCCESS || resultSize != sizeof(ULONG)) {
userSettings = 0;
}
return avpack | (avRegion & (AV_STANDARD_MASK | AV_REFRESH_MASK)) | (userSettings & ~(AV_STANDARD_MASK | AV_PACK_MASK));
}
// Xbox code will set this address via AvSetSavedDataAddress

View File

@ -79,6 +79,14 @@ void* GetXboxFunctionPointer(std::string functionName)
return g_FunctionHooks[functionName].GetTrampoline();
}
// If we got here, the function wasn't patched, so we can just look it up the HLE cache
// and return the correct offset
auto symbol = g_SymbolAddresses.find(functionName);
if (symbol != g_SymbolAddresses.end()) {
return (void*)symbol->second;
}
// Finally, if none of the above were matched, return nullptr
return nullptr;
}