diff --git a/build_tools b/build_tools index 27df20c41..c21b5b8ab 160000 --- a/build_tools +++ b/build_tools @@ -1 +1 @@ -Subproject commit 27df20c41e9525db6f67e57cb4161bdc8e82c117 +Subproject commit c21b5b8ab64e69a3aaed0cde0618e75f12778059 diff --git a/src/xenia/base/clock_win.cc b/src/xenia/base/clock_win.cc index ba62e0008..faead286c 100644 --- a/src/xenia/base/clock_win.cc +++ b/src/xenia/base/clock_win.cc @@ -36,6 +36,8 @@ uint64_t Clock::QueryHostSystemTime() { return (uint64_t(t.dwHighDateTime) << 32) | t.dwLowDateTime; } -uint32_t Clock::QueryHostUptimeMillis() { return ::GetTickCount(); } +uint32_t Clock::QueryHostUptimeMillis() { + return uint32_t(QueryHostTickCount() / (host_tick_frequency() / 1000)); +} } // namespace xe diff --git a/src/xenia/base/threading.h b/src/xenia/base/threading.h index 527188208..bdf70b9c4 100644 --- a/src/xenia/base/threading.h +++ b/src/xenia/base/threading.h @@ -97,6 +97,20 @@ bool FreeTlsHandle(TlsHandle handle); uintptr_t GetTlsValue(TlsHandle handle); bool SetTlsValue(TlsHandle handle, uintptr_t value); +// A high-resolution timer capable of firing at millisecond-precision. +// All timers created in this way are executed in the same thread so +// callbacks must be kept short or else all timers will be impacted. +class HighResolutionTimer { + public: + virtual ~HighResolutionTimer() = default; + + // Creates a new repeating timer with the given period. + // The given function will be called back as close to the given period as + // possible. + static std::unique_ptr CreateRepeating( + std::chrono::milliseconds period, std::function callback); +}; + // Results for a WaitHandle operation. enum class WaitResult { // The state of the specified object is signaled. diff --git a/src/xenia/base/threading_win.cc b/src/xenia/base/threading_win.cc index da3034bb2..a78454c69 100644 --- a/src/xenia/base/threading_win.cc +++ b/src/xenia/base/threading_win.cc @@ -108,6 +108,44 @@ bool SetTlsValue(TlsHandle handle, uintptr_t value) { return TlsSetValue(handle, reinterpret_cast(value)) ? true : false; } +class Win32HighResolutionTimer : public HighResolutionTimer { + public: + Win32HighResolutionTimer(std::function callback) + : callback_(callback) {} + ~Win32HighResolutionTimer() override { + if (handle_) { + DeleteTimerQueueTimer(nullptr, handle_, INVALID_HANDLE_VALUE); + handle_ = nullptr; + } + } + + bool Initialize(std::chrono::milliseconds period) { + return CreateTimerQueueTimer( + &handle_, nullptr, + [](PVOID param, BOOLEAN timer_or_wait_fired) { + auto timer = + reinterpret_cast(param); + timer->callback_(); + }, + this, 0, DWORD(period.count()), WT_EXECUTEINTIMERTHREAD) + ? true + : false; + } + + private: + HANDLE handle_ = nullptr; + std::function callback_; +}; + +std::unique_ptr HighResolutionTimer::CreateRepeating( + std::chrono::milliseconds period, std::function callback) { + auto timer = std::make_unique(std::move(callback)); + if (!timer->Initialize(period)) { + return nullptr; + } + return std::unique_ptr(timer.release()); +} + template class Win32Handle : public T { public: diff --git a/src/xenia/kernel/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl_module.cc index f0214ba9a..08b5153c9 100644 --- a/src/xenia/kernel/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl_module.cc @@ -14,7 +14,6 @@ #include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" -#include "xenia/base/platform_win.h" #include "xenia/emulator.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/xboxkrnl_private.h" @@ -131,16 +130,11 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) xe::store_and_swap(lpKeTimeStampBundle + 16, Clock::QueryGuestUptimeMillis()); xe::store_and_swap(lpKeTimeStampBundle + 20, 0); - CreateTimerQueueTimer( - ×tamp_timer_, nullptr, - [](PVOID param, BOOLEAN timer_or_wait_fired) { - auto timestamp_bundle = reinterpret_cast(param); - xe::store_and_swap(timestamp_bundle + 16, + timestamp_timer_ = xe::threading::HighResolutionTimer::CreateRepeating( + std::chrono::milliseconds(1), [lpKeTimeStampBundle]() { + xe::store_and_swap(lpKeTimeStampBundle + 16, Clock::QueryGuestUptimeMillis()); - }, - lpKeTimeStampBundle, 0, - 1, // 1ms - WT_EXECUTEINTIMERTHREAD); + }); } std::vector xboxkrnl_exports(4096); @@ -171,9 +165,7 @@ void XboxkrnlModule::RegisterExportTable( export_resolver->RegisterTable("xboxkrnl.exe", &xboxkrnl_exports); } -XboxkrnlModule::~XboxkrnlModule() { - DeleteTimerQueueTimer(nullptr, timestamp_timer_, nullptr); -} +XboxkrnlModule::~XboxkrnlModule() = default; int XboxkrnlModule::LaunchModule(const char* path) { // Create and register the module. We keep it local to this function and diff --git a/src/xenia/kernel/xboxkrnl_module.h b/src/xenia/kernel/xboxkrnl_module.h index f8cbb0c4e..922e440aa 100644 --- a/src/xenia/kernel/xboxkrnl_module.h +++ b/src/xenia/kernel/xboxkrnl_module.h @@ -10,6 +10,9 @@ #ifndef XENIA_KERNEL_XBOXKRNL_MODULE_H_ #define XENIA_KERNEL_XBOXKRNL_MODULE_H_ +#include + +#include "xenia/base/threading.h" #include "xenia/cpu/export_resolver.h" #include "xenia/kernel/objects/xkernel_module.h" #include "xenia/kernel/xboxkrnl_ordinals.h" @@ -17,9 +20,6 @@ // All of the exported functions: #include "xenia/kernel/xboxkrnl_rtl.h" -// TODO(benvanik): switch timer. -typedef void* HANDLE; - namespace xe { namespace kernel { @@ -35,7 +35,7 @@ class XboxkrnlModule : public XKernelModule { int LaunchModule(const char* path); private: - HANDLE timestamp_timer_; + std::unique_ptr timestamp_timer_; }; } // namespace kernel diff --git a/xb.bat b/xb.bat index 5b8005819..f28135805 100644 --- a/xb.bat +++ b/xb.bat @@ -40,7 +40,10 @@ IF %_RESULT% NEQ 0 ( ECHO this script again. GOTO :exit_error ) -CALL %VS14_VCVARSALL% amd64 +1>NUL 2>NUL CMD /c where devenv +IF %ERRORLEVEL% NEQ 0 ( + CALL %VS14_VCVARSALL% amd64 +) SET CLANG_FORMAT="" SET LLVM_CLANG_FORMAT="C:\Program Files (x86)\LLVM\bin\clang-format.exe"