Skip to content

Commit

Permalink
MP1-4100 : Rework Refresh Changer by rework Win32 API on C# and Win7 …
Browse files Browse the repository at this point in the history
…API on C++ side. It fix issue on multi screen setup and also GPU#1 / GPU#2.
  • Loading branch information
Sebastiii committed Aug 5, 2013
1 parent 1f36763 commit 0776e7d
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 70 deletions.
Expand Up @@ -60,7 +60,7 @@ void LogGUID(REFGUID guid)
CoTaskMemFree(str);
}

MPEVRCustomPresenter::MPEVRCustomPresenter(IVMR9Callback* pCallback, IDirect3DDevice9* direct3dDevice, HMONITOR monitor, IBaseFilter** EVRFilter, BOOL pIsWin7):
MPEVRCustomPresenter::MPEVRCustomPresenter(IVMR9Callback* pCallback, IDirect3DDevice9* direct3dDevice, HMONITOR monitor, IBaseFilter** EVRFilter, BOOL pIsWin7, int monitorIdx):
CUnknown(NAME("MPEVRCustomPresenter"), NULL),
m_refCount(1),
m_qScheduledSamples(MAX_SURFACES),
Expand Down Expand Up @@ -98,6 +98,7 @@ MPEVRCustomPresenter::MPEVRCustomPresenter(IVMR9Callback* pCallback, IDirect3DDe
Log("--- v1.6.%d Unicode with DWM queue support --- instance 0x%x", DSHOWHELPER_VERSION, this);
Log("---------- audio renderer enabled ------------- instance 0x%x", this);
}
m_monitorIdx = monitorIdx;
m_hMonitor = monitor;
m_pD3DDev = direct3dDevice;
hr = m_pDXVA2CreateDirect3DDeviceManager9(&m_iResetToken, &m_pDeviceManager);
Expand Down Expand Up @@ -3605,7 +3606,7 @@ BOOL MPEVRCustomPresenter::EstimateRefreshTimings(int numFrames, int threadPrior
dParams.dDetectedScanlineTime = scanLineTime / 10000.0;

m_pD3DDev->GetDisplayMode(0, &m_displayMode); //update this just in case anything has changed...
GetRealRefreshRate(); // update m_dD3DRefreshCycle and m_dD3DRefreshRate values
GetRealRefreshRate(m_monitorIdx); // update m_dD3DRefreshCycle and m_dD3DRefreshRate values

if ((dParams.dEstRefreshCycle < 5.0) || (dParams.dEstRefreshCycle > 100.0)) // just in case it's gone badly wrong...
{
Expand Down Expand Up @@ -4263,12 +4264,12 @@ void MPEVRCustomPresenter::VideoFpsFromSample(IMFSample* pSample)


// get driver refresh rate
void MPEVRCustomPresenter::GetRealRefreshRate()
void MPEVRCustomPresenter::GetRealRefreshRate(int monitorIdx)
{
// Win7
if (m_bIsWin7 && m_pW7GetRefreshRate)
{
m_dD3DRefreshRate = m_pW7GetRefreshRate();
m_dD3DRefreshRate = m_pW7GetRefreshRate(monitorIdx);

if (m_dD3DRefreshRate == -1)
{
Expand Down
Expand Up @@ -179,7 +179,7 @@ class MPEVRCustomPresenter :
{

public:
MPEVRCustomPresenter(IVMR9Callback* pCallback, IDirect3DDevice9* direct3dDevice, HMONITOR monitor, IBaseFilter** EVRFilter, BOOL pIsWin7);
MPEVRCustomPresenter(IVMR9Callback* pCallback, IDirect3DDevice9* direct3dDevice, HMONITOR monitor, IBaseFilter** EVRFilter, BOOL pIsWin7, int MonnitorIdx);
virtual ~MPEVRCustomPresenter();

//IQualProp (stub)
Expand Down Expand Up @@ -344,7 +344,7 @@ friend class StatsRenderer;
void ReturnSample(IMFSample* pSample, BOOL tryNotify, BOOL isWorker);
HRESULT PresentSample(IMFSample* pSample);
void VideoFpsFromSample(IMFSample* pSample);
void GetRealRefreshRate();
void GetRealRefreshRate(int monitorIdx);
LONGLONG GetDelayToRasterTarget(LONGLONG *targetTime, LONGLONG *offsetTime);
void DwmEnableMMCSSOnOff(bool enable);
bool BufferMoreSamples();
Expand Down Expand Up @@ -457,6 +457,7 @@ friend class StatsRenderer;
int m_regFPSLimV;
int m_regFPSLimH;
bool m_bOddFrame;
int m_monitorIdx;

int m_nNextSyncOffset;
LONGLONG nsSampleTime;
Expand Down
4 changes: 2 additions & 2 deletions DirectShowFilters/DirectShowHelper/source/dshowhelper.cpp
Expand Up @@ -630,7 +630,7 @@ HRESULT MyGetService(IUnknown* punkObject, REFGUID guidService, REFIID riid, LPV
}


BOOL EvrInit(IVMR9Callback* callback, DWORD dwD3DDevice, IBaseFilter** evrFilter, DWORD monitor)
BOOL EvrInit(IVMR9Callback* callback, DWORD dwD3DDevice, IBaseFilter** evrFilter, DWORD monitor, int monitorIdx)
{
HRESULT hr;
m_RenderPrefix = _T("evr");
Expand All @@ -651,7 +651,7 @@ BOOL EvrInit(IVMR9Callback* callback, DWORD dwD3DDevice, IBaseFilter** evrFilter

#ifndef DEFAULT_PRESENTER

m_evrPresenter = new MPEVRCustomPresenter(callback, m_pDevice, (HMONITOR)monitor, evrFilter, IsWin7());
m_evrPresenter = new MPEVRCustomPresenter(callback, m_pDevice, (HMONITOR)monitor, evrFilter, IsWin7(), monitorIdx);
m_pVMR9Filter = (*evrFilter);

CComQIPtr<IMFVideoRenderer> pRenderer = m_pVMR9Filter;
Expand Down
2 changes: 1 addition & 1 deletion DirectShowFilters/DirectShowHelper/source/dshowhelper.h
Expand Up @@ -74,7 +74,7 @@ typedef HRESULT __stdcall TDwmGetCompositionTimingInfo(HWND hwnd, __out DWM_TIMI
extern TDwmGetCompositionTimingInfo* m_pDwmGetCompositionTimingInfo;


typedef double __stdcall TW7GetRefreshRate();
typedef double __cdecl TW7GetRefreshRate(int monitorIdx);
extern TW7GetRefreshRate* m_pW7GetRefreshRate;

typedef HANDLE __stdcall TAvSetMmThreadCharacteristicsW(LPCWSTR TaskName, LPDWORD TaskIndex);
Expand Down
Expand Up @@ -22,69 +22,83 @@
#include "Win7RefreshRateHelper.h"

// Get current refresh rate on Win7
double W7GetRefreshRate()
double W7GetRefreshRate(int monitorIdx)
{
UINT32 uNumPathArrayElements = 0;
UINT32 uNumPathArrayElements = 0;
UINT32 uNumModeInfoArrayElements = 0;
DISPLAYCONFIG_PATH_INFO* pPathInfoArray = NULL;
DISPLAYCONFIG_MODE_INFO* pModeInfoArray = NULL;
DISPLAYCONFIG_TOPOLOGY_ID* pCurrentTopologyId = NULL;
LONG result;
double refreshRate = -1;
DISPLAY_DEVICE displayDevice;
displayDevice.cb = sizeof(DISPLAY_DEVICE);
DEVMODE devMode;
devMode.dmSize = sizeof(DEVMODE);
DEVMODE *paDeviceMode;

if(EnumDisplayDevices(NULL, monitorIdx, &displayDevice, 0))
{
EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
}
paDeviceMode = &devMode;

// Get size of buffers for QueryDisplayConfig
result = GetDisplayConfigBufferSizes(QDC_ALL_PATHS, &uNumPathArrayElements, &uNumModeInfoArrayElements);
if (result != 0)
{
return(refreshRate);
}
result = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &uNumPathArrayElements, &uNumModeInfoArrayElements);
if (result != 0)
{
return(refreshRate);
}

// allocate memory for QueryDisplayConfig buffers
pPathInfoArray = (DISPLAYCONFIG_PATH_INFO*)calloc(uNumPathArrayElements, sizeof(DISPLAYCONFIG_PATH_INFO));
if (pPathInfoArray == NULL)
{
{
return(refreshRate);
}

pModeInfoArray = (DISPLAYCONFIG_MODE_INFO*)calloc(uNumModeInfoArrayElements, sizeof(DISPLAYCONFIG_MODE_INFO));
if (pModeInfoArray == NULL)
{
{
// freeing memory
free(pPathInfoArray);
return(refreshRate);
}

// get display configuration
result = QueryDisplayConfig(QDC_ALL_PATHS,
result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,
&uNumPathArrayElements, pPathInfoArray,
&uNumModeInfoArrayElements, pModeInfoArray,
pCurrentTopologyId);
if (result == 0)
{
// Get information from first active target path
// TODO: add support for multiple displays (presenter doesn't know active display)
for(int i=0; i < (int)uNumPathArrayElements; i++)
{
if (pPathInfoArray[i].flags == DISPLAYCONFIG_PATH_ACTIVE)
if (result == 0)
{
//// Get information from active target path and based on current dimension (support for multiple displays)
for (UINT i = 0; i < uNumPathArrayElements; ++i)
{
UINT iModIdx = pPathInfoArray[i].sourceInfo.modeInfoIdx;
if(pPathInfoArray[i].flags == DISPLAYCONFIG_PATH_ACTIVE && paDeviceMode[0].dmPosition.x == pModeInfoArray[iModIdx].sourceMode.position.x && paDeviceMode[0].dmPosition.y == pModeInfoArray[iModIdx].sourceMode.position.y)
{
DISPLAYCONFIG_PATH_TARGET_INFO target;
target = pPathInfoArray[i].targetInfo;
LONG numerator = target.refreshRate.Numerator;
LONG denominator = target.refreshRate.Denominator;
refreshRate = (double)numerator/(double)denominator;
break;
}
if(paDeviceMode[0].dmPelsHeight == pModeInfoArray[iModIdx].sourceMode.height && paDeviceMode[0].dmPelsWidth == pModeInfoArray[iModIdx].sourceMode.width)
{
monitorIdx = i;
DISPLAYCONFIG_PATH_TARGET_INFO target;
target = pPathInfoArray[monitorIdx].targetInfo;
LONG numerator = target.refreshRate.Numerator;
LONG denominator = target.refreshRate.Denominator;
refreshRate = (double)numerator/(double)denominator;
break;
}
}
}
}
// freeing memory
free(pPathInfoArray);
free(pModeInfoArray);

return(refreshRate);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpReserved)
{
return TRUE;
}
return TRUE;
}
110 changes: 81 additions & 29 deletions mediaportal/Core/Player/RefreshRateChanger.cs
Expand Up @@ -189,48 +189,99 @@ public static extern ChangeDisplaySettings_Result
public static extern int DwmIsCompositionEnabled(ref int pfEnabled);


/// <summary>
/// Finds the monitorIndex based on current specified screen on its primary monitor
/// </summary>
/// <returns>The monitorIndex that has the specified screen on its primary monitor</returns>
protected static int FindMonitorIndexForScreen()
{
uint deviceNum = 0;
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
displayDevice.cb = (ushort)Marshal.SizeOf(displayDevice);
while (EnumDisplayDevices(null, deviceNum, displayDevice, 0) != 0)
{
if (displayDevice.DeviceName == GUIGraphicsContext.currentScreen.DeviceName)
{
// Set new monitorIndex
GUIGraphicsContext.currentMonitorIdx = (int)deviceNum;
Log.Debug("CycleRefreshRate: return new detected MonitorIndex : {0}", (int)deviceNum);
return (int)deviceNum;
}
++deviceNum;
}
Log.Debug("CycleRefreshRate: return current default MonitorIndex, detection failed to find the new one : {0}",
GUIGraphicsContext.DX9Device.DeviceCaps.AdapterOrdinal);
return GUIGraphicsContext.DX9Device.DeviceCaps.AdapterOrdinal;
}

public static void Win32_SetRefreshRate(uint monitorIndex, uint refreshRate)
{
Win32.DISPLAY_DEVICE displayDevice = new Win32.DISPLAY_DEVICE();
int result = Win32.EnumDisplayDevices(null, monitorIndex, displayDevice, 0);
DISPLAY_DEVICE displayDevice = new DISPLAY_DEVICE();
displayDevice.cb = (ushort)Marshal.SizeOf(displayDevice);
DEVMODE_Display devMode = new DEVMODE_Display();
devMode.dmSize = (ushort)Marshal.SizeOf(devMode);

int result = EnumDisplayDevices(null, monitorIndex, displayDevice, 0);
if (result != 0)
{
Win32.DEVMODE_Display devMode = new Win32.DEVMODE_Display();
devMode.dmFields = Win32.DEVMODE_Fields.DM_DISPLAYFREQUENCY;
devMode.dmDisplayFrequency = refreshRate;
Win32.ChangeDisplaySettings_Result r = Win32.ChangeDisplaySettingsEx(displayDevice.DeviceName, devMode,
IntPtr.Zero,
Win32.ChangeDisplaySettings_Flags.None,
IntPtr.Zero);
Log.Info("CycleRefreshRate: result {0} for refresh rate change {1}Hz", r, refreshRate);
FixDwm();
Log.Debug("CycleRefreshRate: Current MonitorIndex : {0} and current deviceName : {1}", (int) monitorIndex,
GUIGraphicsContext.currentScreen.DeviceName);
if (displayDevice.DeviceName != GUIGraphicsContext.currentScreen.DeviceName)
{
// Analyse monitorIndex to be sure to get on the good one (some multiscreen setup can failed otherwise)
monitorIndex = (uint) FindMonitorIndexForScreen();

// Try to get new displayDevice based on newest detected monitorIndex
result = EnumDisplayDevices(null, monitorIndex, displayDevice, 0);
Log.Debug("CycleRefreshRate: New MonitorIndex : {0} based on current deviceName : {1}", (int) monitorIndex,
GUIGraphicsContext.currentScreen.DeviceName);
}

if (result != 0)
{
result = EnumDisplaySettingsEx(displayDevice.DeviceName, 0, devMode, 2);
if (result != 0)
{
result = EnumDisplaySettingsEx(displayDevice.DeviceName, EnumDisplaySettings_EnumMode.ENUM_CURRENT_SETTINGS, devMode, 2); // EDS_RAWMODE = 2

if (result != 0)
{
// Get current Value
uint Width = devMode.dmPelsWidth;
uint Height = devMode.dmPelsHeight;

//Log.Info("CycleRefreshRate: code result {0} enum devMode", result);
devMode.dmFields = (DEVMODE_Fields.DM_BITSPERPEL | DEVMODE_Fields.DM_PELSWIDTH |
DEVMODE_Fields.DM_PELSHEIGHT | DEVMODE_Fields.DM_DISPLAYFREQUENCY);
devMode.dmBitsPerPel = 32;
devMode.dmPelsWidth = Width;
devMode.dmPelsHeight = Height;
devMode.dmDisplayFrequency = refreshRate;

// First set settings
ChangeDisplaySettings_Result r = ChangeDisplaySettingsEx(displayDevice.DeviceName, devMode,
IntPtr.Zero,
(ChangeDisplaySettings_Flags
.CDS_NORESET |
ChangeDisplaySettings_Flags
.CDS_UPDATEREGISTRY),
IntPtr.Zero);
// Apply settings
r = ChangeDisplaySettingsEx(null, null, IntPtr.Zero, 0, IntPtr.Zero);
Log.Info("CycleRefreshRate: result {0} for refresh rate change {1}Hz", r, refreshRate);
FixDwm();
}
}
}
}
else
{
Log.Info("CycleRefreshRate: unable to change refresh rate {0}Hz for monitor {1}", refreshRate, monitorIndex);
}
}


public static void CycleRefreshRate(uint monitorIndex, double refreshRate)
{
if (OSInfo.OSInfo.Win7OrLater())
{
if (W7RefreshRateHelper.SetRefreshRate(monitorIndex, refreshRate))
{
double newRefreshRate = W7RefreshRateHelper.GetRefreshRate(monitorIndex);
Log.Info("CycleRefreshRate: successfully changed refresh rate to {0}Hz ({1}Hz requested)",
newRefreshRate.ToString("#.###"), refreshRate);
FixDwm();
}
else
{
Log.Info("CycleRefreshRate: unable to change refresh rate to {0}Hz for monitor {1}", refreshRate,
monitorIndex);
}
}
else
{
Win32_SetRefreshRate(monitorIndex, (uint)refreshRate);
}
Expand Down Expand Up @@ -675,6 +726,7 @@ public static void SetRefreshRateBasedOnFPS(double fps, string strFile, MediaTyp
if (newExtCmd.Length == 0)
{
Log.Info("RefreshRateChanger.SetRefreshRateBasedOnFPS: using internal win32 method for changing refreshrate. current is {0}hz, desired is {1}", currentRR, newRR);
Log.Info("RefreshRateChanger AdapterOrdinal value is {0}", (uint)GUIGraphicsContext.DX9Device.DeviceCaps.AdapterOrdinal);
Win32.CycleRefreshRate((uint)GUIGraphicsContext.DX9Device.DeviceCaps.AdapterOrdinal, newRR);
NotifyRefreshRateChanged(newRRDescription, (strFile.Length > 0));
}
Expand All @@ -684,7 +736,7 @@ public static void SetRefreshRateBasedOnFPS(double fps, string strFile, MediaTyp
NotifyRefreshRateChanged(newRRDescription, (strFile.Length > 0));
}

if (GUIGraphicsContext.Vmr9Active)
if (GUIGraphicsContext.Vmr9Active && GUIGraphicsContext.IsEvr)
{
Log.Info("RefreshRateChanger.SetRefreshRateBasedOnFPS: dynamic refresh rate change - notify video renderer");
VMR9Util.g_vmr9.UpdateEVRDisplayFPS();
Expand Down
13 changes: 10 additions & 3 deletions mediaportal/Core/Player/VMR9.cs
Expand Up @@ -86,7 +86,7 @@ public class VMR9Util : IDisposable

[DllImport("dshowhelper.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern unsafe bool EvrInit(IVMR9PresentCallback callback, uint dwD3DDevice,
ref IBaseFilter vmr9Filter, uint monitor);
ref IBaseFilter vmr9Filter, uint monitor, int monitorIdx);

//, uint dwWindow);
[DllImport("dshowhelper.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
Expand Down Expand Up @@ -375,8 +375,15 @@ public bool AddVMR9(IGraphBuilder graphBuilder)
_scene.Init();

if (_useEvr)
{
EvrInit(_scene, (uint)upDevice.ToInt32(), ref _vmr9Filter, (uint)hMonitor.ToInt32());
{
if (GUIGraphicsContext.currentMonitorIdx != -1)
{
EvrInit(_scene, (uint) upDevice.ToInt32(), ref _vmr9Filter, (uint) hMonitor.ToInt32(), GUIGraphicsContext.currentMonitorIdx);
}
else
{
EvrInit(_scene, (uint)upDevice.ToInt32(), ref _vmr9Filter, (uint)hMonitor.ToInt32(), GUIGraphicsContext.DX9Device.DeviceCaps.AdapterOrdinal);
}
hr = new HResult(graphBuilder.AddFilter(_vmr9Filter, "Enhanced Video Renderer"));
Log.Info("VMR9: added EVR Renderer to graph");
}
Expand Down

0 comments on commit 0776e7d

Please sign in to comment.