1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00

[dxgi] Enumerate scaled and centered display modes correctly

Fixes fullscreen mode in Dark Souls 3.
This commit is contained in:
Philip Rebohle 2018-03-24 13:42:23 +01:00
parent 87d6fde5c4
commit 19e0829a37
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 47 additions and 29 deletions

View File

@ -64,16 +64,23 @@ namespace dxvk {
// If no format was specified, fall back to a standard // If no format was specified, fall back to a standard
// SRGB format, which is supported on all devices. // SRGB format, which is supported on all devices.
DXGI_FORMAT formatToMatch = pModeToMatch->Format; DXGI_FORMAT targetFormat = pModeToMatch->Format;
if (formatToMatch == DXGI_FORMAT_UNKNOWN) if (targetFormat == DXGI_FORMAT_UNKNOWN)
formatToMatch = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; targetFormat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
UINT targetRefreshRate = 0;
if (pModeToMatch->RefreshRate.Denominator != 0
&& pModeToMatch->RefreshRate.Numerator != 0) {
targetRefreshRate = pModeToMatch->RefreshRate.Numerator
/ pModeToMatch->RefreshRate.Denominator;
}
// List all supported modes and filter // List all supported modes and filter
// out those we don't actually need // out those we don't actually need
DXGI_MODE_DESC modeToMatch = *pModeToMatch;
UINT modeCount = 0; UINT modeCount = 0;
GetDisplayModeList(formatToMatch, 0, &modeCount, nullptr); GetDisplayModeList(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, nullptr);
if (modeCount == 0) { if (modeCount == 0) {
Logger::err("DxgiOutput::FindClosestMatchingMode: No modes found"); Logger::err("DxgiOutput::FindClosestMatchingMode: No modes found");
@ -81,23 +88,23 @@ namespace dxvk {
} }
std::vector<DXGI_MODE_DESC> modes(modeCount); std::vector<DXGI_MODE_DESC> modes(modeCount);
GetDisplayModeList(formatToMatch, 0, &modeCount, modes.data()); GetDisplayModeList(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, modes.data());
// Filter out modes with different refresh rate for (auto it = modes.begin(); it != modes.end(); ) {
if (modeToMatch.RefreshRate.Denominator != 0 bool skipMode = false;
&& modeToMatch.RefreshRate.Numerator != 0) {
UINT targetRefreshRate = modeToMatch.RefreshRate.Numerator
/ modeToMatch.RefreshRate.Denominator;
for (auto it = modes.begin(); it != modes.end(); ) { // Remove modes with a different refresh rate
if (targetRefreshRate != 0) {
UINT modeRefreshRate = it->RefreshRate.Numerator UINT modeRefreshRate = it->RefreshRate.Numerator
/ it->RefreshRate.Denominator; / it->RefreshRate.Denominator;
skipMode |= modeRefreshRate != targetRefreshRate;
if (modeRefreshRate != targetRefreshRate)
it = modes.erase(it);
else
it++;
} }
// Remove modes with incorrect scaling
if (pModeToMatch->Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
skipMode |= it->Scaling != pModeToMatch->Scaling;
it = skipMode ? modes.erase(it) : ++it;
} }
// No matching modes found // No matching modes found
@ -106,9 +113,10 @@ namespace dxvk {
// Select mode with minimal height+width difference // Select mode with minimal height+width difference
UINT minDifference = UINT_MAX; UINT minDifference = UINT_MAX;
for (auto& mode : modes) { for (auto& mode : modes) {
UINT currDifference = abs((int)(modeToMatch.Width - mode.Width)) UINT currDifference = std::abs(int(pModeToMatch->Width - mode.Width))
+ abs((int)(modeToMatch.Height - mode.Height)); + std::abs(int(pModeToMatch->Height - mode.Height));
if (currDifference < minDifference) { if (currDifference < minDifference) {
minDifference = currDifference; minDifference = currDifference;
@ -125,8 +133,8 @@ namespace dxvk {
return DXGI_ERROR_INVALID_CALL; return DXGI_ERROR_INVALID_CALL;
::MONITORINFOEX monInfo; ::MONITORINFOEX monInfo;
monInfo.cbSize = sizeof(monInfo); monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfo(m_monitor, &monInfo)) { if (!::GetMonitorInfo(m_monitor, &monInfo)) {
Logger::err("DxgiOutput: Failed to query monitor info"); Logger::err("DxgiOutput: Failed to query monitor info");
return E_FAIL; return E_FAIL;
@ -150,14 +158,11 @@ namespace dxvk {
DXGI_MODE_DESC *pDesc) { DXGI_MODE_DESC *pDesc) {
if (pNumModes == nullptr) if (pNumModes == nullptr)
return DXGI_ERROR_INVALID_CALL; return DXGI_ERROR_INVALID_CALL;
if (Flags != 0)
Logger::warn("DxgiOutput::GetDisplayModeList: flags are ignored");
// Query monitor info to get the device name // Query monitor info to get the device name
::MONITORINFOEX monInfo; ::MONITORINFOEX monInfo;
monInfo.cbSize = sizeof(monInfo); monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfo(m_monitor, &monInfo)) { if (!::GetMonitorInfo(m_monitor, &monInfo)) {
Logger::err("DxgiOutput: Failed to query monitor info"); Logger::err("DxgiOutput: Failed to query monitor info");
return E_FAIL; return E_FAIL;
@ -170,6 +175,8 @@ namespace dxvk {
uint32_t srcModeId = 0; uint32_t srcModeId = 0;
uint32_t dstModeId = 0; uint32_t dstModeId = 0;
const bool includeStretchedModes = (Flags & DXGI_ENUM_MODES_SCALING);
while (::EnumDisplaySettings(monInfo.szDevice, srcModeId++, &devMode)) { while (::EnumDisplaySettings(monInfo.szDevice, srcModeId++, &devMode)) {
// Skip interlaced modes altogether // Skip interlaced modes altogether
if (devMode.dmDisplayFlags & DM_INTERLACED) if (devMode.dmDisplayFlags & DM_INTERLACED)
@ -179,6 +186,13 @@ namespace dxvk {
if (devMode.dmBitsPerPel != GetFormatBpp(EnumFormat)) if (devMode.dmBitsPerPel != GetFormatBpp(EnumFormat))
continue; continue;
// Skip stretched modes unless they are requested
const bool isStretched = devMode.dmPelsWidth != UINT(monInfo.rcMonitor.right - monInfo.rcMonitor.left)
|| devMode.dmPelsHeight != UINT(monInfo.rcMonitor.bottom - monInfo.rcMonitor.top);
if (isStretched && !includeStretchedModes)
continue;
// Write back display mode // Write back display mode
if (pDesc != nullptr) { if (pDesc != nullptr) {
if (dstModeId >= *pNumModes) if (dstModeId >= *pNumModes)
@ -190,7 +204,10 @@ namespace dxvk {
mode.RefreshRate = { devMode.dmDisplayFrequency, 1 }; mode.RefreshRate = { devMode.dmDisplayFrequency, 1 };
mode.Format = EnumFormat; mode.Format = EnumFormat;
mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
mode.Scaling = DXGI_MODE_SCALING_CENTERED; mode.Scaling = isStretched
? DXGI_MODE_SCALING_STRETCHED
: DXGI_MODE_SCALING_CENTERED;
pDesc[dstModeId] = mode; pDesc[dstModeId] = mode;
} }

View File

@ -99,17 +99,18 @@ int WINAPI WinMain(HINSTANCE hInstance,
for (auto mode : modes) { for (auto mode : modes) {
std::cout << str::format(" ", std::cout << str::format(" ",
mode.Width, "x", mode.Height, " @ ", mode.Width, "x", mode.Height, " @ ",
mode.RefreshRate.Numerator / mode.RefreshRate.Denominator) << std::endl; mode.RefreshRate.Numerator / mode.RefreshRate.Denominator,
mode.Scaling == DXGI_MODE_SCALING_CENTERED ? " (native)" : "") << std::endl;
//test matching modes //test matching modes
DXGI_MODE_DESC matched_mode{ 0 }; DXGI_MODE_DESC matched_mode{ 0 };
status = output->FindClosestMatchingMode(&mode, &matched_mode, nullptr); status = output->FindClosestMatchingMode(&mode, &matched_mode, nullptr);
if (status != S_OK) { if (status != S_OK) {
std::cerr << "Failed to get DXGI matched mode" << std::endl; std::cerr << "Failed to get matching mode" << std::endl;
return 1; return 1;
} }
if (matched_mode.Width != mode.Width || if (matched_mode.Width != mode.Width ||
matched_mode.Height != mode.Height || matched_mode.Height != mode.Height ||
matched_mode.RefreshRate.Numerator != mode.RefreshRate.Numerator || matched_mode.RefreshRate.Numerator != mode.RefreshRate.Numerator ||