mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-04 07:24:15 +01:00
[dxgi] Return non-exact matches from FindClosestMatchingMode1
This commit is contained in:
parent
3dbccb1b61
commit
cd6e3ffe75
@ -1,4 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -115,22 +116,45 @@ namespace dxvk {
|
|||||||
if (pModeToMatch->Format == DXGI_FORMAT_UNKNOWN && !pConcernedDevice)
|
if (pModeToMatch->Format == DXGI_FORMAT_UNKNOWN && !pConcernedDevice)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
// If no format was specified, fall back to a standard
|
// Both or neither must be zero
|
||||||
// SRGB format, which is supported on all devices.
|
if ((pModeToMatch->Width == 0) ^ (pModeToMatch->Height == 0))
|
||||||
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
DXGI_MODE_DESC activeMode = { };
|
||||||
|
GetMonitorDisplayMode(m_monitor, ENUM_CURRENT_SETTINGS, &activeMode);
|
||||||
|
|
||||||
|
DXGI_MODE_DESC1 defaultMode;
|
||||||
|
defaultMode.Width = 0;
|
||||||
|
defaultMode.Height = 0;
|
||||||
|
defaultMode.RefreshRate = { 0, 0 };
|
||||||
|
defaultMode.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
defaultMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||||
|
defaultMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||||
|
defaultMode.Stereo = pModeToMatch->Stereo;
|
||||||
|
|
||||||
|
if (pModeToMatch->ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED)
|
||||||
|
defaultMode.ScanlineOrdering = activeMode.ScanlineOrdering;
|
||||||
|
|
||||||
|
if (pModeToMatch->Scaling == DXGI_MODE_SCALING_UNSPECIFIED)
|
||||||
|
defaultMode.Scaling = activeMode.Scaling;
|
||||||
|
|
||||||
DXGI_FORMAT targetFormat = pModeToMatch->Format;
|
DXGI_FORMAT targetFormat = pModeToMatch->Format;
|
||||||
|
|
||||||
if (targetFormat == DXGI_FORMAT_UNKNOWN)
|
if (pModeToMatch->Format == DXGI_FORMAT_UNKNOWN) {
|
||||||
targetFormat = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
defaultMode.Format = activeMode.Format;
|
||||||
|
targetFormat = activeMode.Format;
|
||||||
UINT targetRefreshRate = 0;
|
}
|
||||||
|
|
||||||
if (pModeToMatch->RefreshRate.Denominator != 0) {
|
if (!pModeToMatch->Width) {
|
||||||
targetRefreshRate = pModeToMatch->RefreshRate.Numerator
|
defaultMode.Width = activeMode.Width;
|
||||||
/ pModeToMatch->RefreshRate.Denominator;
|
defaultMode.Height = activeMode.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pModeToMatch->RefreshRate.Numerator || !pModeToMatch->RefreshRate.Denominator) {
|
||||||
|
defaultMode.RefreshRate.Numerator = activeMode.RefreshRate.Numerator;
|
||||||
|
defaultMode.RefreshRate.Denominator = activeMode.RefreshRate.Denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all supported modes and filter
|
|
||||||
// out those we don't actually need
|
|
||||||
UINT modeCount = 0;
|
UINT modeCount = 0;
|
||||||
GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, nullptr);
|
GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, nullptr);
|
||||||
|
|
||||||
@ -142,57 +166,21 @@ namespace dxvk {
|
|||||||
std::vector<DXGI_MODE_DESC1> modes(modeCount);
|
std::vector<DXGI_MODE_DESC1> modes(modeCount);
|
||||||
GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, modes.data());
|
GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, modes.data());
|
||||||
|
|
||||||
for (auto it = modes.begin(); it != modes.end(); ) {
|
FilterModesByDesc(modes, *pModeToMatch);
|
||||||
bool skipMode = false;
|
FilterModesByDesc(modes, defaultMode);
|
||||||
|
|
||||||
// Remove modes with a different refresh rate
|
if (modes.empty())
|
||||||
if (targetRefreshRate != 0) {
|
|
||||||
UINT modeRefreshRate = it->RefreshRate.Numerator
|
|
||||||
/ it->RefreshRate.Denominator;
|
|
||||||
skipMode |= modeRefreshRate != targetRefreshRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove modes with incorrect scaling
|
|
||||||
if (pModeToMatch->Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
|
|
||||||
skipMode |= it->Scaling != pModeToMatch->Scaling;
|
|
||||||
|
|
||||||
// Remove modes with incorrect stereo mode
|
|
||||||
skipMode |= it->Stereo != pModeToMatch->Stereo;
|
|
||||||
|
|
||||||
it = skipMode ? modes.erase(it) : ++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matching modes found
|
|
||||||
if (modes.size() == 0)
|
|
||||||
return DXGI_ERROR_NOT_FOUND;
|
return DXGI_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
// If no valid resolution is specified, find the
|
*pClosestMatch = modes[0];
|
||||||
// closest match for the current display resolution
|
|
||||||
UINT targetWidth = pModeToMatch->Width;
|
|
||||||
UINT targetHeight = pModeToMatch->Height;
|
|
||||||
|
|
||||||
if (targetWidth == 0 || targetHeight == 0) {
|
|
||||||
DXGI_MODE_DESC activeMode = { };
|
|
||||||
GetMonitorDisplayMode(m_monitor,
|
|
||||||
ENUM_CURRENT_SETTINGS, &activeMode);
|
|
||||||
|
|
||||||
targetWidth = activeMode.Width;
|
|
||||||
targetHeight = activeMode.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select mode with minimal height+width difference
|
|
||||||
UINT minDifference = std::numeric_limits<unsigned int>::max();
|
|
||||||
|
|
||||||
for (auto mode : modes) {
|
|
||||||
UINT currDifference = std::abs(int(targetWidth - mode.Width))
|
|
||||||
+ std::abs(int(targetHeight - mode.Height));
|
|
||||||
|
|
||||||
if (currDifference <= minDifference) {
|
|
||||||
minDifference = currDifference;
|
|
||||||
*pClosestMatch = mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Logger::debug(str::format(
|
||||||
|
"DXGI: For mode ",
|
||||||
|
pModeToMatch->Width, "x", pModeToMatch->Height, "@",
|
||||||
|
pModeToMatch->RefreshRate.Denominator ? (pModeToMatch->RefreshRate.Numerator / pModeToMatch->RefreshRate.Denominator) : 0,
|
||||||
|
" found closest mode ",
|
||||||
|
pClosestMatch->Width, "x", pClosestMatch->Height, "@",
|
||||||
|
pClosestMatch->RefreshRate.Denominator ? (pClosestMatch->RefreshRate.Numerator / pClosestMatch->RefreshRate.Denominator) : 0));
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,4 +448,59 @@ namespace dxvk {
|
|||||||
return DXGI_ERROR_UNSUPPORTED;
|
return DXGI_ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxgiOutput::FilterModesByDesc(
|
||||||
|
std::vector<DXGI_MODE_DESC1>& Modes,
|
||||||
|
const DXGI_MODE_DESC1& TargetMode) {
|
||||||
|
uint32_t minDiffResolution = 0;
|
||||||
|
uint32_t minDiffRefreshRate = 0;
|
||||||
|
|
||||||
|
if (TargetMode.Width) {
|
||||||
|
minDiffResolution = std::accumulate(
|
||||||
|
Modes.begin(), Modes.end(), std::numeric_limits<uint32_t>::max(),
|
||||||
|
[&TargetMode] (uint32_t current, const DXGI_MODE_DESC1& mode) {
|
||||||
|
uint32_t diff = std::abs(int32_t(TargetMode.Width - mode.Width))
|
||||||
|
+ std::abs(int32_t(TargetMode.Height - mode.Height));
|
||||||
|
return std::min(current, diff);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TargetMode.RefreshRate.Numerator && TargetMode.RefreshRate.Denominator) {
|
||||||
|
minDiffRefreshRate = std::accumulate(
|
||||||
|
Modes.begin(), Modes.end(), std::numeric_limits<uint32_t>::max(),
|
||||||
|
[&TargetMode] (uint32_t current, const DXGI_MODE_DESC1& mode) {
|
||||||
|
uint32_t rate = mode.RefreshRate.Numerator * TargetMode.RefreshRate.Denominator / mode.RefreshRate.Denominator;
|
||||||
|
uint32_t diff = std::abs(int32_t(rate - TargetMode.RefreshRate.Numerator));
|
||||||
|
return std::min(current, diff);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = Modes.begin(); it != Modes.end(); ) {
|
||||||
|
bool skipMode = it->Stereo != TargetMode.Stereo;
|
||||||
|
|
||||||
|
if (TargetMode.ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED)
|
||||||
|
skipMode |= it->ScanlineOrdering != TargetMode.ScanlineOrdering;
|
||||||
|
|
||||||
|
if (TargetMode.Scaling != DXGI_MODE_SCALING_UNSPECIFIED)
|
||||||
|
skipMode |= it->Scaling != TargetMode.Scaling;
|
||||||
|
|
||||||
|
if (TargetMode.Format != DXGI_FORMAT_UNKNOWN)
|
||||||
|
skipMode |= it->Scaling != TargetMode.Scaling;
|
||||||
|
|
||||||
|
if (TargetMode.Width) {
|
||||||
|
uint32_t diff = std::abs(int32_t(TargetMode.Width - it->Width))
|
||||||
|
+ std::abs(int32_t(TargetMode.Height - it->Height));
|
||||||
|
skipMode |= diff != minDiffResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TargetMode.RefreshRate.Numerator && TargetMode.RefreshRate.Denominator) {
|
||||||
|
uint32_t rate = it->RefreshRate.Numerator * TargetMode.RefreshRate.Denominator / it->RefreshRate.Denominator;
|
||||||
|
uint32_t diff = std::abs(int32_t(rate - TargetMode.RefreshRate.Numerator));
|
||||||
|
skipMode |= diff != minDiffRefreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = skipMode ? Modes.erase(it) : ++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,10 @@ namespace dxvk {
|
|||||||
Com<DxgiAdapter> m_adapter = nullptr;
|
Com<DxgiAdapter> m_adapter = nullptr;
|
||||||
HMONITOR m_monitor = nullptr;
|
HMONITOR m_monitor = nullptr;
|
||||||
|
|
||||||
|
static void FilterModesByDesc(
|
||||||
|
std::vector<DXGI_MODE_DESC1>& Modes,
|
||||||
|
const DXGI_MODE_DESC1& TargetMode);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user