1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-18 02:52:10 +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
// SRGB format, which is supported on all devices.
DXGI_FORMAT formatToMatch = pModeToMatch->Format;
DXGI_FORMAT targetFormat = pModeToMatch->Format;
if (formatToMatch == DXGI_FORMAT_UNKNOWN)
formatToMatch = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
if (targetFormat == DXGI_FORMAT_UNKNOWN)
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
// out those we don't actually need
DXGI_MODE_DESC modeToMatch = *pModeToMatch;
UINT modeCount = 0;
GetDisplayModeList(formatToMatch, 0, &modeCount, nullptr);
GetDisplayModeList(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, nullptr);
if (modeCount == 0) {
Logger::err("DxgiOutput::FindClosestMatchingMode: No modes found");
@ -81,23 +88,23 @@ namespace dxvk {
}
std::vector<DXGI_MODE_DESC> modes(modeCount);
GetDisplayModeList(formatToMatch, 0, &modeCount, modes.data());
// Filter out modes with different refresh rate
if (modeToMatch.RefreshRate.Denominator != 0
&& modeToMatch.RefreshRate.Numerator != 0) {
UINT targetRefreshRate = modeToMatch.RefreshRate.Numerator
/ modeToMatch.RefreshRate.Denominator;
GetDisplayModeList(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, modes.data());
for (auto it = modes.begin(); it != modes.end(); ) {
bool skipMode = false;
for (auto it = modes.begin(); it != modes.end(); ) {
// Remove modes with a different refresh rate
if (targetRefreshRate != 0) {
UINT modeRefreshRate = it->RefreshRate.Numerator
/ it->RefreshRate.Denominator;
if (modeRefreshRate != targetRefreshRate)
it = modes.erase(it);
else
it++;
skipMode |= modeRefreshRate != targetRefreshRate;
}
// 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
@ -106,9 +113,10 @@ namespace dxvk {
// Select mode with minimal height+width difference
UINT minDifference = UINT_MAX;
for (auto& mode : modes) {
UINT currDifference = abs((int)(modeToMatch.Width - mode.Width))
+ abs((int)(modeToMatch.Height - mode.Height));
UINT currDifference = std::abs(int(pModeToMatch->Width - mode.Width))
+ std::abs(int(pModeToMatch->Height - mode.Height));
if (currDifference < minDifference) {
minDifference = currDifference;
@ -125,8 +133,8 @@ namespace dxvk {
return DXGI_ERROR_INVALID_CALL;
::MONITORINFOEX monInfo;
monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfo(m_monitor, &monInfo)) {
Logger::err("DxgiOutput: Failed to query monitor info");
return E_FAIL;
@ -150,14 +158,11 @@ namespace dxvk {
DXGI_MODE_DESC *pDesc) {
if (pNumModes == nullptr)
return DXGI_ERROR_INVALID_CALL;
if (Flags != 0)
Logger::warn("DxgiOutput::GetDisplayModeList: flags are ignored");
// Query monitor info to get the device name
::MONITORINFOEX monInfo;
monInfo.cbSize = sizeof(monInfo);
if (!::GetMonitorInfo(m_monitor, &monInfo)) {
Logger::err("DxgiOutput: Failed to query monitor info");
return E_FAIL;
@ -170,6 +175,8 @@ namespace dxvk {
uint32_t srcModeId = 0;
uint32_t dstModeId = 0;
const bool includeStretchedModes = (Flags & DXGI_ENUM_MODES_SCALING);
while (::EnumDisplaySettings(monInfo.szDevice, srcModeId++, &devMode)) {
// Skip interlaced modes altogether
if (devMode.dmDisplayFlags & DM_INTERLACED)
@ -179,6 +186,13 @@ namespace dxvk {
if (devMode.dmBitsPerPel != GetFormatBpp(EnumFormat))
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
if (pDesc != nullptr) {
if (dstModeId >= *pNumModes)
@ -190,7 +204,10 @@ namespace dxvk {
mode.RefreshRate = { devMode.dmDisplayFrequency, 1 };
mode.Format = EnumFormat;
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;
}

View File

@ -99,17 +99,18 @@ int WINAPI WinMain(HINSTANCE hInstance,
for (auto mode : modes) {
std::cout << str::format(" ",
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
DXGI_MODE_DESC matched_mode{ 0 };
status = output->FindClosestMatchingMode(&mode, &matched_mode, nullptr);
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;
}
if (matched_mode.Width != mode.Width ||
matched_mode.Height != mode.Height ||
matched_mode.RefreshRate.Numerator != mode.RefreshRate.Numerator ||