diff --git a/src/Common/EmuEEPROM.cpp b/src/Common/EmuEEPROM.cpp index 56d38dbc9..9331dfa03 100644 --- a/src/Common/EmuEEPROM.cpp +++ b/src/Common/EmuEEPROM.cpp @@ -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 diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 05fb43e4b..5d3867b05 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -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; + } } // ****************************************************************** diff --git a/src/CxbxKrnl/EmuD3D8Types.h b/src/CxbxKrnl/EmuD3D8Types.h index 6c6386289..a2d62f863 100644 --- a/src/CxbxKrnl/EmuD3D8Types.h +++ b/src/CxbxKrnl/EmuD3D8Types.h @@ -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; diff --git a/src/CxbxKrnl/EmuKrnlAv.cpp b/src/CxbxKrnl/EmuKrnlAv.cpp index 1da404f75..ca91f4093 100644 --- a/src/CxbxKrnl/EmuKrnlAv.cpp +++ b/src/CxbxKrnl/EmuKrnlAv.cpp @@ -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 diff --git a/src/CxbxKrnl/HLEIntercept.cpp b/src/CxbxKrnl/HLEIntercept.cpp index 403f5cfcf..209d78a37 100644 --- a/src/CxbxKrnl/HLEIntercept.cpp +++ b/src/CxbxKrnl/HLEIntercept.cpp @@ -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; }