...
 
......@@ -762,6 +762,8 @@ namespace dxvk {
uint32_t modeIndex = 0;
const auto forcedRatio = Ratio<DWORD>(options.forceAspectRatio);
while (::EnumDisplaySettingsW(monInfo.szDevice, modeIndex++, &devMode)) {
// Skip interlaced modes altogether
if (devMode.dmDisplayFlags & DM_INTERLACED)
......@@ -771,7 +773,7 @@ namespace dxvk {
if (devMode.dmBitsPerPel != GetMonitorFormatBpp(Format))
continue;
if (options.disableUltraWide && Ratio<DWORD>(devMode.dmPelsWidth, devMode.dmPelsHeight) == Ratio<DWORD>(64, 27))
if (!forcedRatio.undefined() && Ratio<DWORD>(devMode.dmPelsWidth, devMode.dmPelsHeight) != forcedRatio)
continue;
D3DDISPLAYMODEEX mode;
......
......@@ -59,7 +59,8 @@ namespace dxvk {
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", false);
this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == 0x10de);
this->disableUltraWide = config.getOption<bool> ("d3d9.disableUltraWide", false);
this->forceAspectRatio = config.getOption<std::string>("d3d9.forceAspectRatio", "");
// If we are not Nvidia, enable general hazards.
this->generalHazards = adapter == nullptr || !adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0);
......
......@@ -104,8 +104,8 @@ namespace dxvk {
/// Support VCACHE query
bool supportVCache;
/// Disable UltraWide (64:27) modes
bool disableUltraWide;
/// Forced aspect ratio, disable other modes
std::string forceAspectRatio;
};
}
\ No newline at end of file
......@@ -254,7 +254,7 @@ namespace dxvk {
}} },
/* Senran Kagura Shinovi Versus */
{ R"(\\SKShinoviVersus\.exe$)", {{
{ "d3d9.disableUltraWide", "True" },
{ "d3d9.forceAspectRatio", "16:9" },
}} },
}};
......
#include <numeric>
#include <algorithm>
#include <cstdint>
#include <string>
#include <charconv>
namespace dxvk {
......@@ -13,15 +15,39 @@ namespace dxvk {
public:
Ratio(T num, T denom) {
const T gcd = std::gcd(num, denom);
set(num, denom);
}
Ratio(std::string_view view) {
set(0, 0);
size_t colon = view.find(":");
if (colon == std::string_view::npos)
return;
std::string_view numStr = view.substr(0, colon);
std::string_view denomStr = view.substr(colon + 1);
m_num = num / gcd;
m_denom = denom / gcd;
T num = 0, denom = 0;
std::from_chars(numStr.data(), numStr.data() + numStr.size(), num);
std::from_chars(denomStr.data(), denomStr.data() + denomStr.size(), denom);
set(num, denom);
}
inline T num() const { return m_num; }
inline T denom() const { return m_denom; }
inline bool undefined() const { return m_denom == 0; }
inline void set(T num, T denom) {
const T gcd = std::gcd(num, denom);
m_num = num / gcd;
m_denom = denom / gcd;
}
inline bool operator == (const Ratio& other) const {
return num() == other.num() && denom() == other.denom();
}
......