mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[idd] config: support fractional refresh rates
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client-tests (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
Store refresh rates in millihertz and preserve three decimal places. Advertise exact rational rates while accepting legacy integer values. Accept rates from 23.900 through 1000.000 Hz.
This commit is contained in:
@@ -86,8 +86,8 @@ static const BYTE CTA_COLORIMETRY_BT2020_RGB = (BYTE)(1 << 7);
|
||||
// changing these timings at runtime can make it treat the IDD as a new monitor.
|
||||
static const CSettings::DisplayMode EDID_DISPLAY_MODES[] =
|
||||
{
|
||||
{ 1024, 768, 60, true , false },
|
||||
{ 800, 600, 60, false, false }
|
||||
{ 1024, 768, 60000, true , false },
|
||||
{ 800, 600, 60000, false, false }
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@@ -366,7 +366,8 @@ bool CEdid::GetTiming(Timing& timing, const CSettings::DisplayMode& mode)
|
||||
timing.hActive = mode.width;
|
||||
timing.vActive = mode.height;
|
||||
|
||||
if (timing.hActive == 0 || timing.vActive == 0 || mode.refresh == 0)
|
||||
if (timing.hActive == 0 || timing.vActive == 0 ||
|
||||
mode.refreshMilliHz == 0)
|
||||
return false;
|
||||
|
||||
timing.hBlank = std::max<DWORD>(160,
|
||||
@@ -390,12 +391,11 @@ bool CEdid::GetTiming(Timing& timing, const CSettings::DisplayMode& mode)
|
||||
if (timing.vFront + timing.vSync >= timing.vBlank)
|
||||
return false;
|
||||
|
||||
const UINT64 pixelClock =
|
||||
const UINT64 pixelClockMilliHz =
|
||||
(UINT64)(timing.hActive + timing.hBlank) *
|
||||
(UINT64)(timing.vActive + timing.vBlank) *
|
||||
(UINT64)mode.refresh;
|
||||
const UINT64 pixelClock10KHz = (pixelClock + 5000) / 10000;
|
||||
timing.pixelClock = pixelClock10KHz * 10000;
|
||||
(UINT64)mode.refreshMilliHz;
|
||||
timing.pixelClock = (pixelClockMilliHz + 500) / 1000;
|
||||
return timing.pixelClock != 0;
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ static bool MakeDetailedTiming(
|
||||
timing.hBlank > 4095 || timing.vBlank > 4095)
|
||||
return false;
|
||||
|
||||
const UINT64 pixelClock10KHz = timing.pixelClock / 10000;
|
||||
const UINT64 pixelClock10KHz = (timing.pixelClock + 5000) / 10000;
|
||||
if (pixelClock10KHz == 0 || pixelClock10KHz > 0xffff)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -185,20 +185,20 @@ bool CIndirectDeviceContext::PopulateDefaultModes()
|
||||
if (!GetResolutionMemoryRequirements(configuredMode.width,
|
||||
configuredMode.height, alignment, frameSize, requiredIVSHMEMSize))
|
||||
{
|
||||
DEBUG_WARN("Filtering invalid %s mode %ux%u@%u",
|
||||
DEBUG_WARN("Filtering invalid %s mode %ux%u@%.3f",
|
||||
configuredMode.extraMode ? "extra" : "configured",
|
||||
configuredMode.width, configuredMode.height,
|
||||
configuredMode.refresh);
|
||||
configuredMode.refreshMilliHz / 1000.0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (requiredIVSHMEMSize > m_ivshmem.GetSize())
|
||||
{
|
||||
DEBUG_WARN(
|
||||
"Filtering %s mode %ux%u@%u: requires %llu bytes of IVSHMEM, only %llu bytes are available",
|
||||
"Filtering %s mode %ux%u@%.3f: requires %llu bytes of IVSHMEM, only %llu bytes are available",
|
||||
configuredMode.extraMode ? "extra" : "configured",
|
||||
configuredMode.width, configuredMode.height,
|
||||
configuredMode.refresh,
|
||||
configuredMode.refreshMilliHz / 1000.0,
|
||||
(unsigned long long)requiredIVSHMEMSize,
|
||||
(unsigned long long)m_ivshmem.GetSize());
|
||||
continue;
|
||||
@@ -644,10 +644,11 @@ void CIndirectDeviceContext::ReloadSettings()
|
||||
CSettings::DisplayMode extraMode;
|
||||
if (g_settings.GetExtraMode(extraMode))
|
||||
{
|
||||
const unsigned refresh = g_settings.GetDefaultRefresh();
|
||||
if (extraMode.refresh != refresh)
|
||||
const unsigned refreshMilliHz =
|
||||
g_settings.GetDefaultRefreshMilliHz();
|
||||
if (extraMode.refreshMilliHz != refreshMilliHz)
|
||||
{
|
||||
extraMode.refresh = refresh;
|
||||
extraMode.refreshMilliHz = refreshMilliHz;
|
||||
if (!g_settings.SetExtraMode(extraMode))
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_modeReloadLock);
|
||||
@@ -743,7 +744,38 @@ void CIndirectDeviceContext::OnSwapChainReady()
|
||||
if (replug)
|
||||
m_replugQueued.store(1);
|
||||
else if (doSetMode)
|
||||
g_pipe.SetDisplayMode(mode.width, mode.height, mode.refresh);
|
||||
g_pipe.SetDisplayMode(
|
||||
mode.width, mode.height, mode.refreshMilliHz);
|
||||
}
|
||||
|
||||
static UINT64 GreatestCommonDivisor(UINT64 a, UINT64 b)
|
||||
{
|
||||
while (b)
|
||||
{
|
||||
const UINT64 remainder = a % b;
|
||||
a = b;
|
||||
b = remainder;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static void SetSignalRate(DISPLAYCONFIG_RATIONAL& rate,
|
||||
UINT64 numerator, UINT32 denominator)
|
||||
{
|
||||
const UINT64 divisor = GreatestCommonDivisor(numerator, denominator);
|
||||
numerator /= divisor;
|
||||
denominator /= (UINT32)divisor;
|
||||
|
||||
if (numerator <= UINT32_MAX)
|
||||
{
|
||||
rate.Numerator = (UINT32)numerator;
|
||||
rate.Denominator = denominator;
|
||||
return;
|
||||
}
|
||||
|
||||
rate.Numerator =
|
||||
(UINT32)((numerator + denominator / 2) / denominator);
|
||||
rate.Denominator = 1;
|
||||
}
|
||||
|
||||
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& signal,
|
||||
@@ -761,10 +793,9 @@ static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& signal,
|
||||
signal.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
|
||||
signal.AdditionalSignalInfo.videoStandard = 255;
|
||||
|
||||
signal.vSyncFreq.Numerator = mode.refresh;
|
||||
signal.vSyncFreq.Denominator = 1;
|
||||
signal.hSyncFreq.Numerator = mode.refresh * signal.totalSize.cy;
|
||||
signal.hSyncFreq.Denominator = 1;
|
||||
SetSignalRate(signal.vSyncFreq, mode.refreshMilliHz, 1000);
|
||||
SetSignalRate(signal.hSyncFreq,
|
||||
(UINT64)mode.refreshMilliHz * signal.totalSize.cy, 1000);
|
||||
|
||||
signal.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
|
||||
signal.pixelRate = timing.pixelClock;
|
||||
@@ -964,10 +995,10 @@ void CIndirectDeviceContext::SetResolution(uint32_t width, uint32_t height)
|
||||
}
|
||||
|
||||
CSettings::DisplayMode mode = {};
|
||||
mode.width = width;
|
||||
mode.height = height;
|
||||
mode.refresh = g_settings.GetDefaultRefresh();
|
||||
mode.preferred = true;
|
||||
mode.width = width;
|
||||
mode.height = height;
|
||||
mode.refreshMilliHz = g_settings.GetDefaultRefreshMilliHz();
|
||||
mode.preferred = true;
|
||||
|
||||
bool modesLoaded = false;
|
||||
AcquireSRWLockExclusive(&m_modeReloadLock);
|
||||
|
||||
@@ -287,14 +287,15 @@ void CPipeServer::SetCursorPos(uint32_t x, uint32_t y)
|
||||
WriteMsg(msg);
|
||||
}
|
||||
|
||||
void CPipeServer::SetDisplayMode(uint32_t width, uint32_t height, uint32_t refresh)
|
||||
void CPipeServer::SetDisplayMode(
|
||||
uint32_t width, uint32_t height, uint32_t refreshMilliHz)
|
||||
{
|
||||
LGPipeMsg msg = {};
|
||||
msg.size = sizeof(msg);
|
||||
msg.type = LGPipeMsg::SETDISPLAYMODE;
|
||||
msg.displayMode.width = width;
|
||||
msg.displayMode.height = height;
|
||||
msg.displayMode.refresh = refresh;
|
||||
msg.displayMode.width = width;
|
||||
msg.displayMode.height = height;
|
||||
msg.displayMode.refreshMilliHz = refreshMilliHz;
|
||||
WriteMsg(msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ class CPipeServer
|
||||
void SetDeviceContext(CIndirectDeviceContext* context);
|
||||
|
||||
void SetCursorPos(uint32_t x, uint32_t y);
|
||||
void SetDisplayMode(uint32_t width, uint32_t height, uint32_t refresh);
|
||||
void SetDisplayMode(
|
||||
uint32_t width, uint32_t height, uint32_t refreshMilliHz);
|
||||
void SetGPUStatus(bool software);
|
||||
void ResolutionRejected(uint32_t width, uint32_t height,
|
||||
uint32_t requiredSizeMiB);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "CSettings.h"
|
||||
#include "CDebug.h"
|
||||
#include "DefaultDisplayModes.h"
|
||||
#include "RefreshRate.h"
|
||||
|
||||
#include <wdf.h>
|
||||
|
||||
@@ -34,14 +35,16 @@ CSettings::CSettings()
|
||||
|
||||
CSettings::DisplayModes CSettings::LoadModes()
|
||||
{
|
||||
const unsigned defaultRefresh = GetDefaultRefresh();
|
||||
const unsigned defaultRefreshMilliHz = GetDefaultRefreshMilliHz();
|
||||
DisplayModes displayModes;
|
||||
|
||||
bool hasPreferred = false;
|
||||
DisplayMode m;
|
||||
if (GetExtraMode(m))
|
||||
{
|
||||
DEBUG_INFO("ExtraMode: %ux%u@%u%s", m.width, m.height, m.refresh, m.preferred ? "*" : "");
|
||||
const std::wstring refresh = LGFormatRefreshRate(m.refreshMilliHz);
|
||||
DEBUG_INFO("ExtraMode: %ux%u@%ls%s", m.width, m.height,
|
||||
refresh.c_str(), m.preferred ? "*" : "");
|
||||
displayModes.push_back(m);
|
||||
hasPreferred = m.preferred;
|
||||
}
|
||||
@@ -54,11 +57,12 @@ CSettings::DisplayModes CSettings::LoadModes()
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(DefaultDisplayModes); ++i)
|
||||
{
|
||||
m.width = DefaultDisplayModes[i][0];
|
||||
m.height = DefaultDisplayModes[i][1];
|
||||
m.refresh = defaultRefresh;
|
||||
m.preferred = !hasPreferred && (i == DefaultPreferredDisplayMode);
|
||||
m.extraMode = false;
|
||||
m.width = DefaultDisplayModes[i][0];
|
||||
m.height = DefaultDisplayModes[i][1];
|
||||
m.refreshMilliHz = defaultRefreshMilliHz;
|
||||
m.preferred = !hasPreferred &&
|
||||
(i == DefaultPreferredDisplayMode);
|
||||
m.extraMode = false;
|
||||
displayModes.push_back(m);
|
||||
}
|
||||
return displayModes;
|
||||
@@ -79,8 +83,9 @@ CSettings::DisplayModes CSettings::LoadModes()
|
||||
bool CSettings::SetExtraMode(const DisplayMode& mode)
|
||||
{
|
||||
WCHAR buf[64];
|
||||
_snwprintf_s(buf, _countof(buf), _TRUNCATE, L"%ux%u@%u%s",
|
||||
mode.width, mode.height, mode.refresh,
|
||||
const std::wstring refresh = LGFormatRefreshRate(mode.refreshMilliHz);
|
||||
_snwprintf_s(buf, _countof(buf), _TRUNCATE, L"%ux%u@%ls%s",
|
||||
mode.width, mode.height, refresh.c_str(),
|
||||
mode.preferred ? L"*" : L"");
|
||||
|
||||
HKEY hKey = NULL;
|
||||
@@ -226,24 +231,45 @@ bool CSettings::GetExtraMode(DisplayMode& mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned CSettings::GetDefaultRefresh() const
|
||||
unsigned CSettings::GetDefaultRefreshMilliHz() const
|
||||
{
|
||||
DWORD refresh = 60;
|
||||
DWORD cb = sizeof(refresh);
|
||||
HKEY hKey = nullptr;
|
||||
HKEY hKey = nullptr;
|
||||
LONG status = RegOpenKeyExW(
|
||||
HKEY_LOCAL_MACHINE, LGIDD_REGKEY, 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (status != ERROR_SUCCESS)
|
||||
return 60000;
|
||||
|
||||
LONG st = RegOpenKeyExW(HKEY_LOCAL_MACHINE, LGIDD_REGKEY, 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (st == ERROR_SUCCESS)
|
||||
DWORD type = 0;
|
||||
DWORD size = 0;
|
||||
status = RegQueryValueExW(
|
||||
hKey, L"DefaultRefresh", nullptr, &type, nullptr, &size);
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
DWORD type = 0;
|
||||
st = RegGetValueW(hKey, nullptr, L"DefaultRefresh", RRF_RT_REG_DWORD, &type, &refresh, &cb);
|
||||
RegCloseKey(hKey);
|
||||
return 60000;
|
||||
}
|
||||
|
||||
if (st != ERROR_SUCCESS || refresh < 30 || refresh > 1000)
|
||||
return 60;
|
||||
unsigned refreshMilliHz = 0;
|
||||
if (type == REG_DWORD && size == sizeof(DWORD))
|
||||
{
|
||||
DWORD refresh = 0;
|
||||
status = RegQueryValueExW(hKey, L"DefaultRefresh", nullptr, &type,
|
||||
(LPBYTE)&refresh, &size);
|
||||
if (status == ERROR_SUCCESS && refresh >= 24 && refresh <= 1000)
|
||||
refreshMilliHz = refresh * 1000;
|
||||
}
|
||||
else if ((type == REG_SZ || type == REG_EXPAND_SZ) && size &&
|
||||
size % sizeof(wchar_t) == 0)
|
||||
{
|
||||
std::vector<wchar_t> value(size / sizeof(wchar_t) + 1, L'\0');
|
||||
status = RegQueryValueExW(hKey, L"DefaultRefresh", nullptr, &type,
|
||||
(LPBYTE)value.data(), &size);
|
||||
if (status == ERROR_SUCCESS)
|
||||
LGParseRefreshRate(value.data(), refreshMilliHz);
|
||||
}
|
||||
|
||||
return refresh;
|
||||
RegCloseKey(hKey);
|
||||
return refreshMilliHz ? refreshMilliHz : 60000;
|
||||
}
|
||||
|
||||
bool CSettings::ReadModesValue(std::vector<std::wstring> &out) const
|
||||
@@ -320,16 +346,14 @@ bool CSettings::ParseModeString(const std::wstring& in, DisplayMode& out)
|
||||
|
||||
if (!toUnsigned(s.substr(0, xPos), out.width) ||
|
||||
!toUnsigned(s.substr(xPos + 1, atPos - (xPos + 1)), out.height) ||
|
||||
!toUnsigned(s.substr(atPos + 1), out.refresh))
|
||||
!LGParseRefreshRate(s.substr(atPos + 1), out.refreshMilliHz))
|
||||
return false;
|
||||
|
||||
// sanity check
|
||||
if (out.width < 640 ||
|
||||
out.height < 480 ||
|
||||
out.width > 16384 ||
|
||||
out.height > 16384 ||
|
||||
out.refresh < 30 ||
|
||||
out.refresh > 1000)
|
||||
out.height > 16384)
|
||||
return false;
|
||||
|
||||
out.extraMode = false;
|
||||
|
||||
@@ -30,7 +30,7 @@ class CSettings
|
||||
{
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned refresh;
|
||||
unsigned refreshMilliHz;
|
||||
bool preferred;
|
||||
bool extraMode;
|
||||
};
|
||||
@@ -41,7 +41,7 @@ class CSettings
|
||||
DisplayModes LoadModes();
|
||||
bool SetExtraMode(const DisplayMode & mode);
|
||||
bool GetExtraMode(DisplayMode & mode);
|
||||
unsigned GetDefaultRefresh() const;
|
||||
unsigned GetDefaultRefreshMilliHz() const;
|
||||
|
||||
std::wstring ReadStringValue(const wchar_t* name, const wchar_t* defaultValue = nullptr);
|
||||
bool ReadBoolValue(const wchar_t* name, bool defaultValue = false);
|
||||
|
||||
Reference in New Issue
Block a user