[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / windowing / windows / WinSystemWin32DX.cpp
blob52bea4ac993907555e297706bc9c11e66bcbd067
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "WinSystemWin32DX.h"
11 #include "commons/ilog.h"
12 #include "rendering/dx/RenderContext.h"
13 #include "settings/DisplaySettings.h"
14 #include "settings/Settings.h"
15 #include "settings/SettingsComponent.h"
16 #include "utils/SystemInfo.h"
17 #include "utils/XTimeUtils.h"
18 #include "utils/log.h"
19 #include "windowing/GraphicContext.h"
20 #include "windowing/WindowSystemFactory.h"
22 #include "platform/win32/CharsetConverter.h"
23 #include "platform/win32/WIN32Util.h"
25 #ifndef _M_X64
26 #include "utils/SystemInfo.h"
27 #endif
28 #pragma comment(lib, "dxgi.lib")
29 #include <windows.h>
30 #include <winnt.h>
31 #include <winternl.h>
32 #pragma warning(disable: 4091)
33 #include <d3d10umddi.h>
34 #pragma warning(default: 4091)
35 #include <detours.h>
37 using KODI::PLATFORM::WINDOWS::FromW;
39 using namespace std::chrono_literals;
41 // User Mode Driver hooks definitions
42 void APIENTRY HookCreateResource(D3D10DDI_HDEVICE hDevice, const D3D10DDIARG_CREATERESOURCE* pResource, D3D10DDI_HRESOURCE hResource, D3D10DDI_HRTRESOURCE hRtResource);
43 HRESULT APIENTRY HookCreateDevice(D3D10DDI_HADAPTER hAdapter, D3D10DDIARG_CREATEDEVICE* pCreateData);
44 HRESULT APIENTRY HookOpenAdapter10_2(D3D10DDIARG_OPENADAPTER *pOpenData);
45 static PFND3D10DDI_OPENADAPTER s_fnOpenAdapter10_2{ nullptr };
46 static PFND3D10DDI_CREATEDEVICE s_fnCreateDeviceOrig{ nullptr };
47 static PFND3D10DDI_CREATERESOURCE s_fnCreateResourceOrig{ nullptr };
49 void CWinSystemWin32DX::Register()
51 KODI::WINDOWING::CWindowSystemFactory::RegisterWindowSystem(CreateWinSystem);
54 std::unique_ptr<CWinSystemBase> CWinSystemWin32DX::CreateWinSystem()
56 return std::make_unique<CWinSystemWin32DX>();
59 CWinSystemWin32DX::CWinSystemWin32DX() : CRenderSystemDX()
60 , m_hDriverModule(nullptr)
64 CWinSystemWin32DX::~CWinSystemWin32DX()
68 void CWinSystemWin32DX::PresentRenderImpl(bool rendered)
70 if (rendered)
71 m_deviceResources->Present();
73 if (m_delayDispReset && m_dispResetTimer.IsTimePast())
75 m_delayDispReset = false;
76 OnDisplayReset();
79 if (!rendered)
80 KODI::TIME::Sleep(40ms);
83 bool CWinSystemWin32DX::CreateNewWindow(const std::string& name, bool fullScreen, RESOLUTION_INFO& res)
85 const MONITOR_DETAILS* monitor = GetDisplayDetails(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR));
86 if (!monitor)
87 return false;
89 m_hMonitor = monitor->hMonitor;
90 m_deviceResources = DX::DeviceResources::Get();
91 // setting monitor before creating window for proper hooking into a driver
92 m_deviceResources->SetMonitor(m_hMonitor);
94 return CWinSystemWin32::CreateNewWindow(name, fullScreen, res) && m_deviceResources->HasValidDevice();
97 void CWinSystemWin32DX::SetWindow(HWND hWnd) const
99 m_deviceResources->SetWindow(hWnd);
102 bool CWinSystemWin32DX::DestroyRenderSystem()
104 CRenderSystemDX::DestroyRenderSystem();
106 m_deviceResources->Release();
107 m_deviceResources.reset();
108 return true;
111 void CWinSystemWin32DX::SetDeviceFullScreen(bool fullScreen, RESOLUTION_INFO& res)
113 if (m_deviceResources->SetFullScreen(fullScreen, res))
115 ResolutionChanged();
119 bool CWinSystemWin32DX::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
121 CWinSystemWin32::ResizeWindow(newWidth, newHeight, newLeft, newTop);
122 CRenderSystemDX::OnResize();
124 return true;
127 void CWinSystemWin32DX::OnMove(int x, int y)
129 // do not handle moving at window creation because MonitorFromWindow
130 // returns default system monitor in case of m_hWnd is null
131 if (!m_hWnd)
132 return;
134 HMONITOR newMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
135 if (newMonitor != m_hMonitor)
137 MONITOR_DETAILS* details = GetDisplayDetails(newMonitor);
139 if (!details)
140 return;
142 CDisplaySettings::GetInstance().SetMonitor(KODI::PLATFORM::WINDOWS::FromW(details->MonitorNameW));
143 m_deviceResources->SetMonitor(newMonitor);
144 m_hMonitor = newMonitor;
147 // Save window position if not fullscreen
148 if (!IsFullScreen() && (m_nLeft != x || m_nTop != y))
150 m_nLeft = x;
151 m_nTop = y;
152 const auto settings = CServiceBroker::GetSettingsComponent()->GetSettings();
153 settings->SetInt(SETTING_WINDOW_LEFT, x);
154 settings->SetInt(SETTING_WINDOW_TOP, y);
155 settings->Save();
159 bool CWinSystemWin32DX::DPIChanged(WORD dpi, RECT windowRect) const
161 // on Win10 FCU the OS keeps window size exactly the same size as it was
162 if (CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin10_1709))
163 return true;
165 m_deviceResources->SetDpi(dpi);
166 if (!IsAlteringWindow())
167 return __super::DPIChanged(dpi, windowRect);
169 return true;
172 void CWinSystemWin32DX::ReleaseBackBuffer()
174 m_deviceResources->ReleaseBackBuffer();
177 void CWinSystemWin32DX::CreateBackBuffer()
179 m_deviceResources->CreateBackBuffer();
182 void CWinSystemWin32DX::ResizeDeviceBuffers()
184 m_deviceResources->ResizeBuffers();
187 bool CWinSystemWin32DX::IsStereoEnabled()
189 return m_deviceResources->IsStereoEnabled();
192 void CWinSystemWin32DX::OnScreenChange(HMONITOR monitor)
194 m_deviceResources->SetMonitor(monitor);
197 bool CWinSystemWin32DX::ChangeResolution(const RESOLUTION_INFO &res, bool forceChange)
199 bool changed = CWinSystemWin32::ChangeResolution(res, forceChange);
200 // this is a try to fix FCU issue after changing resolution
201 if (m_deviceResources && changed)
202 m_deviceResources->ResizeBuffers();
203 return changed;
206 void CWinSystemWin32DX::OnResize(int width, int height)
208 if (!m_IsAlteringWindow)
209 ReleaseBackBuffer();
211 m_deviceResources->SetLogicalSize(static_cast<float>(width), static_cast<float>(height));
213 if (!m_IsAlteringWindow)
214 CreateBackBuffer();
217 bool CWinSystemWin32DX::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
219 bool const result = CWinSystemWin32::SetFullScreen(fullScreen, res, blankOtherDisplays);
220 CRenderSystemDX::OnResize();
221 return result;
224 void CWinSystemWin32DX::UninitHooks()
226 // uninstall
227 if (!s_fnOpenAdapter10_2)
228 return;
230 DetourTransactionBegin();
231 DetourUpdateThread(GetCurrentThread());
232 DetourDetach(reinterpret_cast<void**>(&s_fnOpenAdapter10_2), HookOpenAdapter10_2);
233 DetourTransactionCommit();
234 if (m_hDriverModule)
236 FreeLibrary(m_hDriverModule);
237 m_hDriverModule = nullptr;
241 void CWinSystemWin32DX::InitHooks(IDXGIOutput* pOutput)
243 DXGI_OUTPUT_DESC outputDesc;
244 if (!pOutput || FAILED(pOutput->GetDesc(&outputDesc)))
245 return;
247 DISPLAY_DEVICEW displayDevice;
248 displayDevice.cb = sizeof(DISPLAY_DEVICEW);
249 DWORD adapter = 0;
250 bool deviceFound = false;
252 // delete exiting hooks.
253 if (s_fnOpenAdapter10_2)
254 UninitHooks();
256 // enum devices to find matched
257 while (EnumDisplayDevicesW(nullptr, adapter, &displayDevice, 0))
259 if (wcscmp(displayDevice.DeviceName, outputDesc.DeviceName) == 0)
261 deviceFound = true;
262 break;
264 adapter++;
266 if (!deviceFound)
267 return;
269 CLog::LogF(LOGDEBUG, "Hooking into UserModeDriver on device {}. ",
270 FromW(displayDevice.DeviceKey));
271 const wchar_t* keyName =
272 #ifndef _M_X64
273 // on x64 system and x32 build use UserModeDriverNameWow key
274 CSysInfo::GetKernelBitness() == 64 ? keyName = L"UserModeDriverNameWow" :
275 #endif // !_WIN64
276 L"UserModeDriverName";
278 DWORD dwType = REG_MULTI_SZ;
279 HKEY hKey = nullptr;
280 wchar_t value[1024];
281 DWORD valueLength = sizeof(value);
282 LSTATUS lstat;
284 // to void \Registry\Machine at the beginning, we use shifted pointer at 18
285 if (ERROR_SUCCESS == (lstat = RegOpenKeyExW(HKEY_LOCAL_MACHINE, displayDevice.DeviceKey + 18, 0, KEY_READ, &hKey))
286 && ERROR_SUCCESS == (lstat = RegQueryValueExW(hKey, keyName, nullptr, &dwType, (LPBYTE)&value, &valueLength)))
288 // 1. registry value has a list of drivers for each API with the following format: dx9\0dx10\0dx11\0dx12\0\0
289 // 2. we split the value by \0
290 std::vector<std::wstring> drivers;
291 const wchar_t* pValue = value;
292 while (*pValue)
294 drivers.push_back(std::wstring(pValue));
295 pValue += drivers.back().size() + 1;
297 // no entries in the registry
298 if (drivers.empty())
299 return;
300 // 3. we take only first three values (dx12 driver isn't needed if it exists ofc)
301 if (drivers.size() > 3)
302 drivers = std::vector<std::wstring>(drivers.begin(), drivers.begin() + 3);
303 // 4. and then iterate with reverse order to start iterate with the best candidate for d3d11 driver
304 for (auto it = drivers.rbegin(); it != drivers.rend(); ++it)
306 m_hDriverModule = LoadLibraryW(it->c_str());
307 if (m_hDriverModule != nullptr)
309 s_fnOpenAdapter10_2 = reinterpret_cast<PFND3D10DDI_OPENADAPTER>(GetProcAddress(m_hDriverModule, "OpenAdapter10_2"));
310 if (s_fnOpenAdapter10_2 != nullptr)
312 DetourTransactionBegin();
313 DetourUpdateThread(GetCurrentThread());
314 DetourAttach(reinterpret_cast<void**>(&s_fnOpenAdapter10_2), HookOpenAdapter10_2);
315 if (NO_ERROR == DetourTransactionCommit())
316 // install and activate hook into a driver
318 CLog::LogF(LOGDEBUG, "D3D11 hook installed and activated.");
319 break;
321 else
323 CLog::Log(LOGDEBUG, __FUNCTION__": Unable to install and activate D3D11 hook.");
324 s_fnOpenAdapter10_2 = nullptr;
325 FreeLibrary(m_hDriverModule);
326 m_hDriverModule = nullptr;
333 if (lstat != ERROR_SUCCESS)
334 CLog::LogF(LOGDEBUG, "error open registry key with error {}.", lstat);
336 if (hKey != nullptr)
337 RegCloseKey(hKey);
340 void CWinSystemWin32DX::FixRefreshRateIfNecessary(const D3D10DDIARG_CREATERESOURCE* pResource) const
342 if (pResource && pResource->pPrimaryDesc)
344 float refreshRate = RATIONAL_TO_FLOAT(pResource->pPrimaryDesc->ModeDesc.RefreshRate);
345 if (refreshRate > 10.0f && refreshRate < 300.0f)
347 // interlaced
348 if (pResource->pPrimaryDesc->ModeDesc.ScanlineOrdering > DXGI_DDI_MODE_SCANLINE_ORDER_PROGRESSIVE)
349 refreshRate /= 2;
351 uint32_t refreshNum, refreshDen;
352 DX::GetRefreshRatio(static_cast<uint32_t>(floor(m_fRefreshRate)), &refreshNum, &refreshDen);
353 float diff = fabs(refreshRate - static_cast<float>(refreshNum) / static_cast<float>(refreshDen)) / refreshRate;
354 CLog::LogF(LOGDEBUG,
355 "refreshRate: {:0.4f}, desired: {:0.4f}, deviation: {:.5f}, fixRequired: {}, {}",
356 refreshRate, m_fRefreshRate, diff, (diff > 0.0005 && diff < 0.1) ? "yes" : "no",
357 pResource->pPrimaryDesc->Flags);
358 if (diff > 0.0005 && diff < 0.1)
360 pResource->pPrimaryDesc->ModeDesc.RefreshRate.Numerator = refreshNum;
361 pResource->pPrimaryDesc->ModeDesc.RefreshRate.Denominator = refreshDen;
362 if (pResource->pPrimaryDesc->ModeDesc.ScanlineOrdering > DXGI_DDI_MODE_SCANLINE_ORDER_PROGRESSIVE)
363 pResource->pPrimaryDesc->ModeDesc.RefreshRate.Numerator *= 2;
364 CLog::LogF(LOGDEBUG, "refreshRate fix applied -> {:0.3f}",
365 RATIONAL_TO_FLOAT(pResource->pPrimaryDesc->ModeDesc.RefreshRate));
371 void APIENTRY HookCreateResource(D3D10DDI_HDEVICE hDevice, const D3D10DDIARG_CREATERESOURCE* pResource, D3D10DDI_HRESOURCE hResource, D3D10DDI_HRTRESOURCE hRtResource)
373 if (pResource && pResource->pPrimaryDesc)
375 DX::Windowing()->FixRefreshRateIfNecessary(pResource);
377 s_fnCreateResourceOrig(hDevice, pResource, hResource, hRtResource);
380 HRESULT APIENTRY HookCreateDevice(D3D10DDI_HADAPTER hAdapter, D3D10DDIARG_CREATEDEVICE* pCreateData)
382 HRESULT hr = s_fnCreateDeviceOrig(hAdapter, pCreateData);
383 if (pCreateData->pDeviceFuncs->pfnCreateResource)
385 CLog::LogF(LOGDEBUG, "hook into pCreateData->pDeviceFuncs->pfnCreateResource");
386 s_fnCreateResourceOrig = pCreateData->pDeviceFuncs->pfnCreateResource;
387 pCreateData->pDeviceFuncs->pfnCreateResource = HookCreateResource;
389 return hr;
392 HRESULT APIENTRY HookOpenAdapter10_2(D3D10DDIARG_OPENADAPTER *pOpenData)
394 HRESULT hr = s_fnOpenAdapter10_2(pOpenData);
395 if (pOpenData->pAdapterFuncs->pfnCreateDevice)
397 CLog::LogF(LOGDEBUG, "hook into pOpenData->pAdapterFuncs->pfnCreateDevice");
398 s_fnCreateDeviceOrig = pOpenData->pAdapterFuncs->pfnCreateDevice;
399 pOpenData->pAdapterFuncs->pfnCreateDevice = HookCreateDevice;
401 return hr;
404 bool CWinSystemWin32DX::IsHDRDisplay()
406 return (CWIN32Util::GetWindowsHDRStatus() != HDR_STATUS::HDR_UNSUPPORTED);
409 HDR_STATUS CWinSystemWin32DX::GetOSHDRStatus()
411 return CWIN32Util::GetWindowsHDRStatus();
414 HDR_STATUS CWinSystemWin32DX::ToggleHDR()
416 return m_deviceResources->ToggleHDR();
419 bool CWinSystemWin32DX::IsHDROutput() const
421 return m_deviceResources->IsHDROutput();
424 bool CWinSystemWin32DX::IsTransferPQ() const
426 return m_deviceResources->IsTransferPQ();
429 void CWinSystemWin32DX::SetHdrMetaData(DXGI_HDR_METADATA_HDR10& hdr10) const
431 m_deviceResources->SetHdrMetaData(hdr10);
434 void CWinSystemWin32DX::SetHdrColorSpace(const DXGI_COLOR_SPACE_TYPE colorSpace) const
436 m_deviceResources->SetHdrColorSpace(colorSpace);
439 DEBUG_INFO_RENDER CWinSystemWin32DX::GetDebugInfo()
441 return m_deviceResources->GetDebugInfo();
444 bool CWinSystemWin32DX::SupportsVideoSuperResolution()
446 return m_deviceResources->IsSuperResolutionSupported();