1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include "common/Console.h"
#include "common/FileSystem.h"
#include "common/HostSys.h"
#include "common/RedtapeWindows.h"
#include "common/StringUtil.h"
#include "common/Threading.h"
#include "common/WindowInfo.h"
#include <mmsystem.h>
#include <timeapi.h>
#include <VersionHelpers.h>
// If anything tries to read this as an initializer, we're in trouble.
static const LARGE_INTEGER lfreq = []() {
LARGE_INTEGER ret = {};
QueryPerformanceFrequency(&ret);
return ret;
}();
// This gets leaked... oh well.
static thread_local HANDLE s_sleep_timer;
static thread_local bool s_sleep_timer_created = false;
static HANDLE GetSleepTimer()
{
if (s_sleep_timer_created)
return s_sleep_timer;
s_sleep_timer_created = true;
s_sleep_timer = CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!s_sleep_timer)
s_sleep_timer = CreateWaitableTimer(nullptr, TRUE, nullptr);
return s_sleep_timer;
}
u64 GetTickFrequency()
{
return lfreq.QuadPart;
}
u64 GetCPUTicks()
{
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
return count.QuadPart;
}
u64 GetPhysicalMemory()
{
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullTotalPhys;
}
u64 GetAvailablePhysicalMemory()
{
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullAvailPhys;
}
// Calculates the Windows OS Version and processor architecture, and returns it as a
// human-readable string. :)
std::string GetOSVersionString()
{
std::string retval;
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
if (IsWindows10OrGreater())
{
retval = "Microsoft ";
retval += IsWindowsServer() ? "Windows Server 2016+" : "Windows 10+";
}
else
retval = "Unsupported Operating System!";
return retval;
}
bool Common::InhibitScreensaver(bool inhibit)
{
EXECUTION_STATE flags = ES_CONTINUOUS;
if (inhibit)
flags |= ES_DISPLAY_REQUIRED;
SetThreadExecutionState(flags);
return true;
}
void Common::SetMousePosition(int x, int y)
{
SetCursorPos(x, y);
}
bool Common::AttachMousePositionCb(std::function<void(int, int)> cb)
{
// We use raw input messages which are handled by the windows message loop.
// The alternative is to use a low-level mouse hook, but this passes Windows all mouse messages to PCSX2.
// If PCSX2 hangs, or you attach a debugger, the mouse will stop working system-wide.
return true;
}
void Common::DetachMousePositionCb()
{
}
bool Common::PlaySoundAsync(const char* path)
{
const std::wstring wpath = FileSystem::GetWin32Path(path);
return PlaySoundW(wpath.c_str(), NULL, SND_ASYNC | SND_NODEFAULT);
}
void Threading::Sleep(int ms)
{
::Sleep(ms);
}
void Threading::SleepUntil(u64 ticks)
{
// This is definitely sub-optimal, but there's no way to sleep until a QPC timestamp on Win32.
const s64 diff = static_cast<s64>(ticks - GetCPUTicks());
if (diff <= 0)
return;
const HANDLE hTimer = GetSleepTimer();
if (!hTimer)
return;
const u64 one_hundred_nanos_diff = (static_cast<u64>(diff) * 10000000ULL) / GetTickFrequency();
if (one_hundred_nanos_diff == 0)
return;
LARGE_INTEGER fti;
fti.QuadPart = -static_cast<s64>(one_hundred_nanos_diff);
if (SetWaitableTimer(hTimer, &fti, 0, nullptr, nullptr, FALSE))
{
WaitForSingleObject(hTimer, INFINITE);
return;
}
}
|