From d2984a05ca41e27ff5ba7216ec291525a7487258 Mon Sep 17 00:00:00 2001 From: Andrii Borziak Date: Wed, 24 Aug 2022 13:51:58 -0700 Subject: [PATCH 1/3] Added DynamicRefreshRateSample --- .../DynamicRefreshRateTool/.gitignore | 12 + .../DynamicRefreshRateTool/AnimationPage.cpp | 57 +++++ .../DynamicRefreshRateTool/AnimationPage.h | 34 +++ .../DynamicRefreshRateTool/AnimationPage.idl | 22 ++ .../DynamicRefreshRateTool/AnimationPage.xaml | 64 +++++ .../DynamicRefreshRateTool/App.idl | 17 ++ .../DynamicRefreshRateTool/App.xaml | 42 ++++ .../DynamicRefreshRateTool/App.xaml.cpp | 67 +++++ .../DynamicRefreshRateTool/App.xaml.h | 30 +++ .../Assets/LockScreenLogo.scale-200.png | Bin 0 -> 3541 bytes .../Assets/SplashScreen.scale-200.png | Bin 0 -> 47523 bytes .../Assets/Square150x150Logo.scale-200.png | Bin 0 -> 22440 bytes .../Assets/Square44x44Logo.scale-200.png | Bin 0 -> 5596 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 2422 bytes .../Assets/StoreLogo.png | Bin 0 -> 3616 bytes .../Assets/Wide310x150Logo.scale-200.png | Bin 0 -> 16223 bytes .../DynamicRefreshRateTool/ChartPage.cpp | 161 ++++++++++++ .../DynamicRefreshRateTool/ChartPage.h | 67 +++++ .../DynamicRefreshRateTool/ChartPage.idl | 24 ++ .../DynamicRefreshRateTool/ChartPage.xaml | 37 +++ .../DynamicRefreshRateTool.sln | 43 ++++ .../DynamicRefreshRateTool.vcxproj | 238 ++++++++++++++++++ .../DynamicRefreshRateTool.vcxproj.filters | 63 +++++ .../DynamicRefreshRateTool/MainWindow.idl | 22 ++ .../DynamicRefreshRateTool/MainWindow.xaml | 125 +++++++++ .../MainWindow.xaml.cpp | 132 ++++++++++ .../DynamicRefreshRateTool/MainWindow.xaml.h | 54 ++++ .../Package.appxmanifest | 48 ++++ .../DynamicRefreshRateTool/README.md | 54 ++++ .../RefreshRateLogger.cpp | 114 +++++++++ .../RefreshRateLogger.h | 39 +++ .../RefreshRateMeter.cpp | 185 ++++++++++++++ .../DynamicRefreshRateTool/RefreshRateMeter.h | 83 ++++++ .../DynamicRefreshRateTool/app.manifest | 15 ++ .../DynamicRefreshRateTool/packages.config | 8 + .../DynamicRefreshRateTool/pch.cpp | 15 ++ .../Composition/DynamicRefreshRateTool/pch.h | 73 ++++++ 37 files changed, 1945 insertions(+) create mode 100644 Samples/Composition/DynamicRefreshRateTool/.gitignore create mode 100644 Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/AnimationPage.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl create mode 100644 Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml create mode 100644 Samples/Composition/DynamicRefreshRateTool/App.idl create mode 100644 Samples/Composition/DynamicRefreshRateTool/App.xaml create mode 100644 Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/App.xaml.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/LockScreenLogo.scale-200.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/SplashScreen.scale-200.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/Square150x150Logo.scale-200.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.scale-200.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/StoreLogo.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/Assets/Wide310x150Logo.scale-200.png create mode 100644 Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/ChartPage.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/ChartPage.idl create mode 100644 Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml create mode 100644 Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln create mode 100644 Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj create mode 100644 Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters create mode 100644 Samples/Composition/DynamicRefreshRateTool/MainWindow.idl create mode 100644 Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml create mode 100644 Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest create mode 100644 Samples/Composition/DynamicRefreshRateTool/README.md create mode 100644 Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h create mode 100644 Samples/Composition/DynamicRefreshRateTool/app.manifest create mode 100644 Samples/Composition/DynamicRefreshRateTool/packages.config create mode 100644 Samples/Composition/DynamicRefreshRateTool/pch.cpp create mode 100644 Samples/Composition/DynamicRefreshRateTool/pch.h diff --git a/Samples/Composition/DynamicRefreshRateTool/.gitignore b/Samples/Composition/DynamicRefreshRateTool/.gitignore new file mode 100644 index 000000000..96e03d03f --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/.gitignore @@ -0,0 +1,12 @@ +.vs/ + +Debug/ +Release/ + +x64/ + +packages/ + +Generated Files/ + +AppPackages/ diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp new file mode 100644 index 000000000..624d86804 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp @@ -0,0 +1,57 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" +#include "AnimationPage.h" +#if __has_include("AnimationPage.g.cpp") +#include "AnimationPage.g.cpp" +#endif + +using namespace winrt; +using namespace Microsoft::UI::Xaml; +using namespace Microsoft::UI::Xaml::Controls::Primitives; + +namespace winrt::DynamicRefreshRateTool::implementation +{ + const float DEFAULT_ROTATION_SPEED = 3600; + + AnimationPage::AnimationPage() + { + InitializeComponent(); + myStoryBoard().Begin(); + } + + void AnimationPage::Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) + { + auto buttonClicked = sender.try_as(); + + for (auto button : { Button1(), Button2(), Button3() }) { + if ((buttonClicked == button) != button.IsChecked().GetBoolean()) { + button.OnToggle(); + } + } + + if (Button1().IsChecked().GetBoolean()) { + RotationAnimation().To(DEFAULT_ROTATION_SPEED / 2); + } + + if (Button2().IsChecked().GetBoolean()) { + RotationAnimation().To(DEFAULT_ROTATION_SPEED); + } + + if (Button3().IsChecked().GetBoolean()) { + RotationAnimation().To(DEFAULT_ROTATION_SPEED * 2); + } + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.h b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.h new file mode 100644 index 000000000..bdd410e83 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.h @@ -0,0 +1,34 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once + +#include "AnimationPage.g.h" + +namespace winrt::DynamicRefreshRateTool::implementation +{ + struct AnimationPage : AnimationPageT + { + AnimationPage(); + + void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + }; +} + +namespace winrt::DynamicRefreshRateTool::factory_implementation +{ + struct AnimationPage : AnimationPageT + { + }; +} diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl new file mode 100644 index 000000000..2a498bda0 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl @@ -0,0 +1,22 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +namespace DynamicRefreshRateTool +{ + [default_interface] + runtimeclass AnimationPage : Microsoft.UI.Xaml.Controls.Page + { + AnimationPage(); + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml new file mode 100644 index 000000000..aad6bede1 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x0.5 Speed + x1 Speed + x2 Speed + + + + + + + + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/App.idl b/Samples/Composition/DynamicRefreshRateTool/App.idl new file mode 100644 index 000000000..3a52f73ac --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/App.idl @@ -0,0 +1,17 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +namespace DynamicRefreshRateTool +{ +} diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml b/Samples/Composition/DynamicRefreshRateTool/App.xaml new file mode 100644 index 000000000..d849f1495 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/App.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + #20A0A0A0 + #20A0A0A0 + + + + + + + + + + + + + + + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp b/Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp new file mode 100644 index 000000000..1f835f0c7 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp @@ -0,0 +1,67 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" + +#include "App.xaml.h" +#include "MainWindow.xaml.h" + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Microsoft::UI::Xaml; +using namespace Microsoft::UI::Xaml::Controls; +using namespace Microsoft::UI::Xaml::Navigation; +using namespace DynamicRefreshRateTool; +using namespace DynamicRefreshRateTool::implementation; +using namespace Windows::UI::ViewManagement; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + +#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + UnhandledException([this](IInspectable const&, UnhandledExceptionEventArgs const& e) + { + if (IsDebuggerPresent()) + { + auto errorMessage = e.Message(); + __debugbreak(); + } + }); +#endif +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points +/// will be used such as when the application is launched to open a specific file. +/// +/// Details about the launch request and process. +void App::OnLaunched(LaunchActivatedEventArgs const&) +{ + window = make(); + + // Set default window size on startup + HWND hwnd{ nullptr }; + window.try_as()->get_WindowHandle(&hwnd); + auto winid = winrt::Microsoft::UI::GetWindowIdFromWindow(hwnd); + auto appWindow = winrt::Microsoft::UI::Windowing::AppWindow::GetFromWindowId(winid); + double scale = GetDpiForWindow(hwnd) / 96.0; + appWindow.Resize({ static_cast(800 * scale), static_cast(600 * scale) }); + + window.Activate(); +} diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml.h b/Samples/Composition/DynamicRefreshRateTool/App.xaml.h new file mode 100644 index 000000000..e5f45e356 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/App.xaml.h @@ -0,0 +1,30 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once + +#include "App.xaml.g.h" + +namespace winrt::DynamicRefreshRateTool::implementation +{ + struct App : AppT + { + App(); + + void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); + + private: + winrt::Microsoft::UI::Xaml::Window window{ nullptr }; + }; +} diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/LockScreenLogo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..dcfd9bf7bbc221669a4be81d5d01d86b677a800d GIT binary patch literal 3541 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 W$W!tUfZkae8t`*%m5OIpk^c{u?wG#- literal 0 HcmV?d00001 diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square150x150Logo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..e8bde635255e33a5a07325dbceea8f1cd7a298e8 GIT binary patch literal 22440 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 literal 0 HcmV?d00001 diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..b11f0951f08e018d481b06cc68d2bdfdfe7dd194 GIT binary patch literal 5596 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 literal 0 HcmV?d00001 diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..b0bf1927d90eb4380abea90bb3c5b659cbe4a2c0 GIT binary patch literal 2422 zcmbVO3slr*7LG*}QI7RhtF$E>+6t7JOft`8XHb}#3g{>zT5#85NHR=hW)hNt0agTo zTC|H@x5cdp%43zaMYN@bMYm!F)RsyM%DN~XgtEStDpptNDadAcjJC&pbITKzG%h?&0D$RpT-PL^s8~dJ z9%W);9kHh6ILX?i1jQ!M(li?Xv3@H zzQiXTWN|n+9EP1vr_?EzvV0F9=P#8reB0?gh+Z{xj#4h+xFc@fojF_-Lw+q2xOcm1@7vza(Ats%p;b>Z5Q+Sd#rix+u zyRzYMJx>!3mXBds>%>7tO@s{U^{#`#z<}2nJHUCIOL9h+HL?BO1({Kuy>iSTe;`1rzqv|7pLHXT&Zf ztUsGa?3PDTOt6HC842Ps3*)^MMkJ1}tW3yQ-%>0ohWf}LAipptPv(*f#UC&u7fuX`w~Z|4_AKFo88YoCHsYCW>eIzcdCsp}|-x@K3WGRqC+; zGyxZNM2!na*6TyOccaqj6XxuE{sd~8{} zwbsw~L!Sb_WeSz$vuD=jycYm92X!pk9}=JlijCU&K3G1veSY)d`JS0O*ODI;*lbZh zP)mN-UX*j-Aak+G_niZsn-(2&UL8EL=kn9D?|i1czNJOyyxMhl-^fVu?p4sqjYY3_ z^p8vjW|me|kcU3G|I(q9is&G<|COd+K$>e@D{-h1+w;KIbLnDlY>0G$cVS&!ZSCs= zK(XL={=$XZ1*gAhsZL1t4<4-l!`y3=^NJU1wI^?!>%Ilt)Mj&^#oNr7`HKcKG_3ZL~1IDJ54DX7I_sVFgd3YLFTdMZC^w(F+!_Re~ z9&M$)+oUbkf9}0FqrYmEqGRr{&68?nAN~GeZrmA*-WVZ0`tfrPOi_KI=?i7pW7pd`jdez3q9uccd-PcX<2hJF~wj^UU7DG}e>^9?$s4`k-I!t@tkE z-8rh}w)=1IZulWWwRdAh;@L^9!vo5sAo9HJ(vH&IbsN@KzwE2uKJ4?t@fP~|l{cZ> z?5){tRd201w~3uY_weodKoxuOOLFQ1{=m1hb3fH(pNiXeY0s^tf$x>%c+w@=l_%t- zGrqiTRC+Bet3{WXt@(HN{pAb4?#xJ=qN(r7;o?oni}jh;7;Ado<*yo6q}q$>9_UW| zJwC%LxO3`9eStFWsomCH;lZtqQ@bk_UI&l2@e6DYxhm?10yF4d4?2j8gA_Ir4TMym~*!h0S8=eI-D+g;v)M4}1G_m#* zar^eqFK-WfIkVv2S0x^B1Gi!IjxEtE3-`Caw9Itnfc3jYo03BFp59)6{QIGu{a;6Z z7|INly)q;I#;LeBHE+ICeiJHfF4*edbN{K_j*mwk7S`VcvL>y&l@-#tyzCj*mr;aq Lg`qlZL(abdA{v;# literal 0 HcmV?d00001 diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/StoreLogo.png b/Samples/Composition/DynamicRefreshRateTool/Assets/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..8a55cd73c1be36b1c53674e17f2a51a143338599 GIT binary patch literal 3616 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 BqH_QM literal 0 HcmV?d00001 diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp b/Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp new file mode 100644 index 000000000..6edc04d62 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp @@ -0,0 +1,161 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" +#include "ChartPage.h" +#if __has_include("ChartPage.g.cpp") +#include "ChartPage.g.cpp" +#endif + +using namespace winrt; +using namespace Microsoft::UI::Xaml; +using namespace Microsoft::UI::Xaml::Controls; +using namespace Windows::Foundation; + +namespace winrt::DynamicRefreshRateTool::implementation +{ + ChartPage::ChartPage() + { + InitializeComponent(); + } + + float ChartPage::QpcTimeToXCoordinate(int64_t qpcTime) + { + if (m_fpsHistory.empty()) + { + return 0; + } + + float width = static_cast(FpsCanvas().ActualWidth()); + float relativeTime = static_cast(m_fpsHistory.back().tick - qpcTime) / RefreshRateMeter::Instance().GetFrequency(); + return width - relativeTime * width / m_displayHistorySeconds; + } + + float ChartPage::FpsToYCoordinate(float fps) + { + float height = static_cast(FpsCanvas().ActualHeight()); + return height - fps / m_maxFps / 1.3f * height; + } + + void ChartPage::RefreshChart() + { + + m_fpsHistory = RefreshRateMeter::Instance().GetRecentHistory(0, m_displayHistorySeconds * RefreshRateMeter::Instance().GetFrequency(), m_aggregationSize); + + if (m_fpsHistory.empty()) + { + return; + } + + m_maxFps *= 0.95; + for (auto& fpsValue : m_fpsHistory) + { + m_maxFps = max(m_maxFps, fpsValue.refreshRate); + } + + RefreshDashedLines(); + + auto points = FpsChart().Points(); + + points.Clear(); + + Point firstPoint = { 0, FpsToYCoordinate(m_fpsHistory[0].refreshRate) }; + points.Append(firstPoint); + + for (auto& fpsValue : m_fpsHistory) + { + points.Append({ QpcTimeToXCoordinate(fpsValue.tick), FpsToYCoordinate(fpsValue.refreshRate) }); + } + + points.Append({ (float)FpsCanvas().ActualWidth(), FpsToYCoordinate(m_fpsHistory.back().refreshRate) }); + + points.Append({ (float)FpsCanvas().ActualWidth() + 10, (float)FpsCanvas().ActualHeight() + 10 }); + points.Append({ -10, (float)FpsCanvas().ActualHeight() + 10 }); + + RefreshTooltip(); + } + + void ChartPage::RefreshDashedLines() + { + DashLine().Points().Clear(); + + bool leftToRight = 0; + for (float level : {60.0f, 120.0f, 240.0f}) + { + float y = FpsToYCoordinate(level); + + if (y < 0) continue; + + DashLine().Points().Append({ leftToRight ? -10.0f : (float)FpsCanvas().ActualWidth() + 10.0f, y }); + DashLine().Points().Append({ !leftToRight ? -10.0f : (float)FpsCanvas().ActualWidth() + 10.0f, y }); + + leftToRight = !leftToRight; + } + } + + void ChartPage::RefreshTooltip() + { + // Place tooltip offscreen + FpsCanvas().SetLeft(FpsTooltip(), -1000); + FpsCanvas().SetLeft(FpsIndicator(), -1000); + + if (!m_mousePosition.has_value()) + { + return; + } + + float nearestDistance = 1e9; + RefreshRateMeter::DataPoint nearestFpsValue = { 0, 0 }; + + for (auto fpsValue : m_fpsHistory) + { + float distance = fabs(QpcTimeToXCoordinate(fpsValue.tick) - m_mousePosition->X); + if (distance < nearestDistance) + { + nearestDistance = distance; + nearestFpsValue = fpsValue; + } + } + + // Place tooltip to new coordinbates + float y = FpsToYCoordinate(nearestFpsValue.refreshRate); + FpsCanvas().SetLeft(FpsTooltip(), m_mousePosition->X); + FpsCanvas().SetTop(FpsTooltip(), y - 30); + FpsCanvas().SetLeft(FpsIndicator(), m_mousePosition->X - 3); + FpsCanvas().SetTop(FpsIndicator(), y - 3); + FpsTooltipText().Text(winrt::to_hstring(RefreshRateMeter::RefreshRateToString(nearestFpsValue.refreshRate)) + winrt::to_hstring(" FPS")); + } + + void ChartPage::FpsCanvas_PointerMoved(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e) + { + m_mousePosition = e.GetCurrentPoint(*this).Position(); + RefreshTooltip(); + } + + void ChartPage::FpsCanvas_PointerExited(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e) + { + m_mousePosition = std::nullopt; + RefreshTooltip(); + } + + void ChartPage::Slider_ValueChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e) + { + m_displayHistorySeconds = e.NewValue(); + } + + void ChartPage::Slider_ValueChanged_1(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e) + { + m_aggregationSize = e.NewValue(); + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.h b/Samples/Composition/DynamicRefreshRateTool/ChartPage.h new file mode 100644 index 000000000..bc2635f0f --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/ChartPage.h @@ -0,0 +1,67 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once + +#include "ChartPage.g.h" + +namespace winrt::DynamicRefreshRateTool::implementation +{ + struct ChartPage : ChartPageT + { + ChartPage(); + + // Mouse events over canvas. + void FpsCanvas_PointerExited(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e); + void FpsCanvas_PointerMoved(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e); + + // Sliders events. + void Slider_ValueChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e); + void Slider_ValueChanged_1(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e); + + void RefreshChart(); + + private: + + // Helper functions to convert fps data values to coordinates on canvas. + float QpcTimeToXCoordinate(int64_t fpsValue); + float FpsToYCoordinate(float fps); + + // Methods that refresh canvas content. + void RefreshDashedLines(); + void RefreshTooltip(); + + // Timer that awakes to refresh chart. + std::future m_monitorFuture; + bool running = true; + + // Optional mouse position. Set to nullopt if mouse is not over the canvas. + std::optional m_mousePosition; + + // Latest fps data history and query parameters that can be tweaked in UI. + std::vector m_fpsHistory; + float m_displayHistorySeconds = 16.0f; + int m_aggregationSize = 1; + + // Maximal fps value in recorded history. + float m_maxFps = 60.0f; + }; +} + +namespace winrt::DynamicRefreshRateTool::factory_implementation +{ + struct ChartPage : ChartPageT + { + }; +} diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.idl b/Samples/Composition/DynamicRefreshRateTool/ChartPage.idl new file mode 100644 index 000000000..90100404a --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/ChartPage.idl @@ -0,0 +1,24 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +namespace DynamicRefreshRateTool +{ + [default_interface] + runtimeclass ChartPage : Microsoft.UI.Xaml.Controls.Page + { + ChartPage(); + + void RefreshChart(); + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml b/Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml new file mode 100644 index 000000000..4aaeebd26 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + FPS: 60.0 + + + + + + + Displayed FPS History (Seconds) + + + + Smoothing (Number of frames to average) + + + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln new file mode 100644 index 000000000..800b7b615 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32802.440 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DynamicRefreshRateTool", "DynamicRefreshRateTool.vcxproj", "{FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|arm64 = Debug|arm64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|arm64 = Release|arm64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|arm64.ActiveCfg = Debug|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|arm64.Build.0 = Debug|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|arm64.Deploy.0 = Debug|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x64.ActiveCfg = Debug|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x64.Build.0 = Debug|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x64.Deploy.0 = Debug|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x86.ActiveCfg = Debug|Win32 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x86.Build.0 = Debug|Win32 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Debug|x86.Deploy.0 = Debug|Win32 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|arm64.ActiveCfg = Release|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|arm64.Build.0 = Release|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|arm64.Deploy.0 = Release|arm64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x64.ActiveCfg = Release|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x64.Build.0 = Release|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x64.Deploy.0 = Release|x64 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x86.ActiveCfg = Release|Win32 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x86.Build.0 = Release|Win32 + {FDBC6BD5-F2E8-46BC-89D7-324B16E872B2}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {46A26428-CD90-4D63-8567-EBDE8ED66261} + EndGlobalSection +EndGlobal diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj new file mode 100644 index 000000000..6b083f094 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj @@ -0,0 +1,238 @@ + + + + + + + true + true + true + {fdbc6bd5-f2e8-46bc-89d7-324b16e872b2} + DynamicRefreshRateTool + DynamicRefreshRateTool + + $(RootNamespace) + en-US + 16.0 + false + true + Windows Store + 10.0 + 10.0 + 10.0.17763.0 + true + true + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + arm64 + + + Release + Win32 + + + Release + x64 + + + Release + arm64 + + + + Application + v143 + v142 + Unicode + true + + + true + true + + + false + true + false + + + + + + + + + False + False + False + True + Never + 0 + True + SHA256 + testcertbeta.pfx + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + Designer + + + + + + + + AnimationPage.xaml + Code + + + ChartPage.xaml + Code + + + + App.xaml + + + MainWindow.xaml + + + + + + + + Designer + + + Designer + + + + + + AnimationPage.xaml + Code + + + ChartPage.xaml + Code + + + Create + + + App.xaml + + + MainWindow.xaml + + + + + + + + AnimationPage.xaml + Code + + + Code + App.xaml + + + ChartPage.xaml + Code + + + Code + MainWindow.xaml + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters new file mode 100644 index 000000000..df3cb64ed --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + {fdbc6bd5-f2e8-46bc-89d7-324b16e872b2} + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.idl b/Samples/Composition/DynamicRefreshRateTool/MainWindow.idl new file mode 100644 index 000000000..3f02e69e0 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/MainWindow.idl @@ -0,0 +1,22 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +namespace DynamicRefreshRateTool +{ + [default_interface] + runtimeclass MainWindow : Microsoft.UI.Xaml.Window + { + MainWindow(); + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml new file mode 100644 index 000000000..802c7378d --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Folder is not selected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp new file mode 100644 index 000000000..4d7123dc9 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp @@ -0,0 +1,132 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" +#include "MainWindow.xaml.h" +#if __has_include("MainWindow.g.cpp") +#include "MainWindow.g.cpp" +#endif + +using namespace winrt; +using namespace Microsoft::UI::Xaml; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace winrt::DynamicRefreshRateTool::implementation +{ + + MainWindow::MainWindow() + { + InitializeComponent(); + + ExtendsContentIntoTitleBar(true); + SetTitleBar(AppTitleBar()); + + m_updateFuture = std::async(std::launch::async | std::launch::deferred, + [this]() + { + while (running) + { + std::this_thread::sleep_for(std::chrono::milliseconds(75)); + DispatcherQueue().TryEnqueue( + [this]() + { + FpsText().Text(winrt::to_hstring(RefreshRateMeter::RefreshRateToString(RefreshRateMeter::Instance().GetCurrentRefreshRate()))); + if (Chart().Visibility() == Visibility::Visible) + { + Chart().RefreshChart(); + } + } + ); + } + } + ); + + Closed( + [&](auto, auto) + { + this->running = false; + m_updateFuture.wait(); + } + ); + } + + void MainWindow::Page_KeyUp(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& e) + { + if (e.Key() == winrt::Windows::System::VirtualKey::B) + { + BoostToggleSwitch().IsOn(!BoostToggleSwitch().IsOn()); + } + if (e.Key() == winrt::Windows::System::VirtualKey::L && LoggingToggleSwitch().IsEnabled()) + { + LoggingToggleSwitch().IsOn(!LoggingToggleSwitch().IsOn()); + } + } + + winrt::Windows::Foundation::IAsyncAction MainWindow::ChooseFolder_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) + { + Windows::Storage::Pickers::FolderPicker picker; + picker.ViewMode(Windows::Storage::Pickers::PickerViewMode::List); + picker.SuggestedStartLocation(Windows::Storage::Pickers::PickerLocationId::ComputerFolder); + picker.as()->Initialize(GetActiveWindow()); + + + if (auto loggingFolder = co_await picker.PickSingleFolderAsync()) + { + m_loggingFolder = loggingFolder; + FolderPath().Text(m_loggingFolder.Path()); + FolderPath().Visibility(Visibility::Visible); + FolderNotSelected().Visibility(Visibility::Collapsed); + LoggingToggleSwitch().IsEnabled(true); + } + + } + + void MainWindow::BoostToggled(IInspectable const& sender, RoutedEventArgs const& args) + { + DCompositionBoostCompositorClock(BoostToggleSwitch().IsOn()); + if (IsLogging()) + { + m_logger->BoostStateChanged(BoostToggleSwitch().IsOn()); + } + } + + void MainWindow::StartLogging() + { + m_logger.emplace(std::wstring(m_loggingFolder.Path().c_str())); + } + + void MainWindow::StopLogging() + { + m_logger = std::nullopt; + } + + bool MainWindow::IsLogging() + { + return LoggingToggleSwitch().IsOn() && m_logger; + } + + void MainWindow::LoggingToggleSwitch_Toggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) + { + if (LoggingToggleSwitch().IsOn()) + { + StartLogging(); + } + else + { + StopLogging(); + } + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h new file mode 100644 index 000000000..2f5bb265c --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h @@ -0,0 +1,54 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once + +#include "MainWindow.g.h" + +namespace winrt::DynamicRefreshRateTool::implementation +{ + struct MainWindow : MainWindowT + { + MainWindow(); + + void BoostToggled(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args); + + void Page_KeyUp(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& e); + + winrt::Windows::Foundation::IAsyncAction ChooseFolder_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + + void LoggingToggleSwitch_Toggled(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + + private: + + void StartLogging(); + + void StopLogging(); + + bool IsLogging(); + + std::optional m_logger; + winrt::Windows::Storage::StorageFolder m_loggingFolder = nullptr; + + std::future m_updateFuture; + bool running = true; + }; +} + +namespace winrt::DynamicRefreshRateTool::factory_implementation +{ + struct MainWindow : MainWindowT + { + }; +} diff --git a/Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest b/Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest new file mode 100644 index 000000000..ef56e7912 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest @@ -0,0 +1,48 @@ + + + + + + + + DynamicRefreshRateTool + microsoft + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/README.md b/Samples/Composition/DynamicRefreshRateTool/README.md new file mode 100644 index 000000000..6c7d04cb8 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/README.md @@ -0,0 +1,54 @@ +--- +page_type: sample +languages: +- cpp +products: +- windows +- windows-api-win32 +- windows-app-sdk +- DXGI +name: DynamicRefreshRateTool sample +urlFragment: DynamicRefreshRateTool-sample +description: Demonstrates how to use APIs related to the Dynamic Refresh Rate feature with WinUI3 applications. +extendedZipContent: +- path: LICENSE +- target: LICENSE +--- + +# DynamicRefreshRateTool sample + +This sample application demonstrates how a **WinUI3** app can interact with the Windows 11 feature [Dynamic Refresh Rate](https://devblogs.microsoft.com/directx/dynamic-refresh-rate/) through various system APIs. It uses these APIs to both demonstrate their functionality and provide a helpful and easy-to-use framework for validating the functionality of Dynamic Refresh Rate on supported devices, both programatically and visually. The main purpose will be to illustrate when the refresh rate of a system changes by going higher and lower. We refer to this functionality as *boosting* and *unboosting.* You can read more about how this feature works in our documentation for the [Compositor Clock API](https://docs.microsoft.com/en-us/windows/win32/directcomp/compositor-clock/compositor-clock'). + +## APIs Used + +**WinUI3** controls are used to build the main user interface of this application, including its windows and buttons. For the animation shown in the animations tab, we use **Microsoft.UI.Composition**. In this iteration of **Microsoft.UI.Composition**, the app's visual scene is self-composed into a single **DXGI SwapChain**. Due to the design of Dynamic Refresh Rate, DXGI SwapChains are mapped to a [virtualized refresh rate](https://docs.microsoft.com/en-us/windows/win32/directcomp/compositor-clock/compositor-clock) by default and are not able to perceive changing vblank cadences of present timings. In build 22502, Windows 11 introduced [DXGIDisableVBlankVirtualization](https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_6/nf-dxgi1_6-dxgidisablevblankvirtualization) which DynamicRefreshRateTool uses to disable the virtualization for the application before the main SwapChain is created, allowing the SwapChain to observe changes in its [IDXGIOutput::WaitForVBlank](https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgioutput-waitforvblank) and present timing as the refresh rate changes from 60Hz to 120Hz and back. We expect many applications that are SwapChain-based will use this method to be able to perceive the Dynamic Refresh Rate. + +The buttons that are used to request boost use the [DCompositionBoostCompositorClock](https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-dcompositionboostcompositorclock) function with a boolean value to indicate whether the application is requesting the system boost or rescinding the request, which we call boosting or unboosting. + +The Statistics tab showcases usage of [Frame statistics](https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nf-dcomp-dcompositiongetstatistics) through DComposition-based statistics API. + +## Dynamic Refresh Rate behavior on different Windows 11 versions + +While using this sample, you may find that boosting may occur at different times when your application does not request it. That is because there is global logic in Windows that will *auto-boost*. In Windows 11 builds before [preview 22557](https://blogs.windows.com/windows-insider/2022/02/16/announcing-windows-11-insider-preview-build-22557/), auto-boosting occurs when GPU Accelerated Ink is drawn, such as by using [DelegatedInkTrailVisual ](https://docs.microsoft.com/en-us/uwp/api/windows.ui.composition.delegatedinktrailvisual?view=winrt-22621) as well as when an application uses [InteractionTracker](https://docs.microsoft.com/en-us/uwp/api/windows.ui.composition.interactions.interactiontracker?view=winrt-22621) to drive animations. After 22557 [Windows will auto-boost for a short duration when it receives pointing input](https://blogs.windows.com/windows-insider/2022/02/16/announcing-windows-11-insider-preview-build-22557/#:~:text=We%E2%80%99re%20expanding%20Dynamic,then%20restart%20Edge.). + +## Prerequisites + +* See [System requirements for Windows app development](https://docs.microsoft.com/windows/apps/windows-app-sdk/system-requirements). +* Make sure that your development environment is set up correctly—see [Install tools for developing apps for Windows 10 and Windows 11](https://docs.microsoft.com/windows/apps/windows-app-sdk/set-up-your-development-environment). + + +## Building and running the sample + +* Open the solution file (`.sln`) in Visual Studio. +* Press Ctrl+Shift+B, or select **Build** \> **Build Solution**. + +In the project properties, select the "Debug" tab, and set the Debugger type for both "Application process" and "Background +task process" to "Native Only". + +## Related Links + +- [Windows App SDK](https://docs.microsoft.com/windows/apps/windows-app-sdk/) +- [Compositor Clock](https://docs.microsoft.com/en-us/windows/win32/directcomp/compositor-clock/compositor-clock) +- [Dynamic Refresh Rate](https://devblogs.microsoft.com/directx/dynamic-refresh-rate/) +- [DXGIDisableVBlankVirtualization](https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_6/nf-dxgi1_6-dxgidisablevblankvirtualization) +- [Windows 11 preview 22557](https://blogs.windows.com/windows-insider/2022/02/16/announcing-windows-11-insider-preview-build-22557/) diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp b/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp new file mode 100644 index 000000000..c434ccf22 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp @@ -0,0 +1,114 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" + +using namespace winrt::DynamicRefreshRateTool; +using namespace std::chrono; + +std::wstring GetFullPathForLoggingFile(std::wstring folderPath) +{ + std::time_t t = std::time(nullptr); + std::tm tm; + ::localtime_s(&tm, &t); + std::stringstream stream; + stream << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); + auto str = stream.str(); + return folderPath + L"\\" + L"FPS Monitor " + std::wstring(str.begin(), str.end()) + L".txt"; +} + +RefreshRateLogger::RefreshRateLogger(std::wstring folderPath) :m_out(GetFullPathForLoggingFile(folderPath)) +{ + WriteLog("Logging started."); + + m_loggerFuture = std::async(std::launch::async | std::launch::deferred, + [this]() + { + int64_t startingFrom = RefreshRateMeter::Instance().GetCurrentTick(); + + int levels = 4; + int fpsLevels[] = { 0, 60, 120, 240 }; + int fpsLevelsFrames[] = { 0, 0, 0, 0, 0 }; + int prevLevel = 0; + int total = 0; + + while (!m_stop) + { + auto history = RefreshRateMeter::Instance().GetHistoryStartingFrom(startingFrom); + for (auto& data : history) + { + int curLevel = 0; + total++; + for (int i = 1; i < levels; i++) + { + if (fabs(fpsLevels[i] - data.refreshRate) < 10) + { + curLevel = i; + break; + } + } + + fpsLevelsFrames[curLevel]++; + + if (curLevel != 0) + { + if (curLevel != prevLevel) + { + WriteLog("Running at " + std::to_string(fpsLevels[curLevel]) + "hz"); + } + + prevLevel = curLevel; + } + } + + if (!history.empty()) + { + startingFrom = history.back().tick; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + + WriteLog("Logging finished."); + WriteLog("Total number of frames captured: " + std::to_string(total)); + for (int i = 1; i < 4; i++) + { + WriteLog("Number of frames at " + std::to_string(fpsLevels[i]) + "hz: " + std::to_string(fpsLevelsFrames[i]) + " (~" + std::to_string(fpsLevelsFrames[i] * 100 / total) + "%)"); + } + WriteLog("Other frames: " + std::to_string(fpsLevelsFrames[0]) + " (~" + std::to_string(fpsLevelsFrames[0] * 100 / total) + "%)"); + } + ); +} + +RefreshRateLogger::~RefreshRateLogger() +{ + m_stop = true; + m_loggerFuture.wait(); +} + +void RefreshRateLogger::BoostStateChanged(bool enabled) +{ + WriteLog(enabled ? "Boost enabled." : "Boost disabled."); +} + +void RefreshRateLogger::WriteLog(std::string message) +{ + std::lock_guard lock(m_mutex); + + std::time_t t = std::time(nullptr); + std::tm tm; + ::localtime_s(&tm, &t); + + m_out << "[" << std::put_time(&tm, "%d-%m-%Y %H:%M:%S") << "] " << message << std::endl; +} diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h b/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h new file mode 100644 index 000000000..a79e8481c --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h @@ -0,0 +1,39 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once +#include "pch.h" + +namespace winrt::DynamicRefreshRateTool { + + class RefreshRateLogger { + public: + RefreshRateLogger(std::wstring folderPath); + + ~RefreshRateLogger(); + + void BoostStateChanged(bool enabled); + + private: + + void WriteLog(std::string message); + + std::ofstream m_out; + std::mutex m_mutex; + + bool m_stop = false; + std::future m_loggerFuture; + }; + +} diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp b/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp new file mode 100644 index 000000000..a666749d9 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp @@ -0,0 +1,185 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" + +using namespace winrt; +using namespace winrt::DynamicRefreshRateTool; + +RefreshRateMeter::RefreshRateMeter() +{ + LARGE_INTEGER frequency = {}; + QueryPerformanceFrequency(&frequency); + m_frequency = frequency.QuadPart; + + // Start monitor thread. + m_monitorFuture = std::async(std::launch::async | std::launch::deferred, [this] { RefreshRateTrackingThread(); }); +} + +RefreshRateMeter::~RefreshRateMeter() +{ + m_shouldStopFpsCalculation = true; + m_monitorFuture.wait(); +} + +float RefreshRateMeter::GetCurrentRefreshRate() const +{ + if (m_deltaHistory.empty()) + { + // If there is no history yet - return default 60 FPS. + return 60.0; + } + + return static_cast(m_frequency) / m_deltaHistory.back().second; +} + +int64_t RefreshRateMeter::GetLastFrameDeltaTicks() const +{ + if (m_deltaHistory.empty()) + { + // If there is no history yet - return default 1/60 delta. + return m_frequency / 60; + } + + return m_deltaHistory.back().second; +} + +int64_t RefreshRateMeter::GetFrequency() const +{ + return m_frequency; +} + +int64_t RefreshRateMeter::GetCurrentTick() const +{ + LARGE_INTEGER currentTime; + QueryPerformanceCounter(¤tTime); + return currentTime.QuadPart; +} + +RefreshRateMeter& RefreshRateMeter::Instance() +{ + static RefreshRateMeter RefreshRateMeter; + return RefreshRateMeter; +} + +std::vector RefreshRateMeter::GetRecentHistory(int64_t offsetTicks, int64_t historyLengthTicks, int aggregationSize, int keepEach) const +{ + if (m_deltaHistory.empty()) + { + return {}; + } + + std::lock_guard guard(m_mutex); + + int lastFrameIndex = static_cast(m_deltaHistory.size()) - 1; + for (int64_t accumulatedTotal = 0; lastFrameIndex >= 0 && accumulatedTotal + m_deltaHistory[lastFrameIndex].second <= offsetTicks; lastFrameIndex--) { + accumulatedTotal += m_deltaHistory[lastFrameIndex].second; + } + + if (lastFrameIndex < 0) + { + return {}; + } + + int firstFrameIndex = lastFrameIndex; + for (int64_t accumulatedTotal = 0; firstFrameIndex >= 0 && accumulatedTotal + m_deltaHistory[firstFrameIndex].second <= historyLengthTicks; firstFrameIndex--) { + accumulatedTotal += m_deltaHistory[firstFrameIndex].second; + } + + if (firstFrameIndex < 0) + { + firstFrameIndex = 0; + } + + std::vector res; + + int64_t aggregatedDelta = 0; + int64_t aggregatedFramesNumber = 0; + + for (int i = lastFrameIndex; i > lastFrameIndex - aggregationSize + 1 && i >= 0; i--) + { + aggregatedDelta += m_deltaHistory[i].second; + aggregatedFramesNumber++; + } + + for (int i = lastFrameIndex; i >= firstFrameIndex; i--) + { + if (i - aggregationSize + 1 >= 0) + { + aggregatedDelta += m_deltaHistory[i - aggregationSize + 1].second; + aggregatedFramesNumber++; + } + + if ((m_currentFrame - (m_deltaHistory.size() - i - 1)) % keepEach == 0) + { + float refreshRate = static_cast(aggregatedFramesNumber * m_frequency) / aggregatedDelta; + res.push_back(DataPoint{ m_deltaHistory[i].first, aggregatedDelta, aggregatedFramesNumber, refreshRate }); + } + + aggregatedDelta -= m_deltaHistory[i].second; + aggregatedFramesNumber--; + } + + std::reverse(res.begin(), res.end()); + + return res; +} + +std::vector RefreshRateMeter::GetHistoryStartingFrom(int64_t startingFrom) const +{ + std::lock_guard guard(m_mutex); + std::vector res; + for (int i = (int)m_deltaHistory.size() - 1; i >= 0 && m_deltaHistory[i].first > startingFrom; i--) + { + res.push_back(DataPoint{ m_deltaHistory[i].first, m_deltaHistory[i].second, 1, static_cast(m_frequency) / m_deltaHistory[i].second }); + } + + std::reverse(res.begin(), res.end()); + + return res; +} + +std::string RefreshRateMeter::RefreshRateToString(float fpsValue) +{ + std::stringstream stream; + // One digit fixed precision (like "60.0"). + stream << std::fixed << std::setprecision(1) << fpsValue; + return stream.str(); +} + +void RefreshRateMeter::RefreshRateTrackingThread() +{ + LARGE_INTEGER prevTime = {}; + + while (!m_shouldStopFpsCalculation) + { + DCompositionWaitForCompositorClock(0, nullptr, INFINITE); + LARGE_INTEGER currentTime{}; + QueryPerformanceCounter(¤tTime); + + if (prevTime.QuadPart != 0) + { + std::lock_guard guard(m_mutex); + m_deltaHistory.push_back({ currentTime.QuadPart, currentTime.QuadPart - prevTime.QuadPart }); + + if (m_deltaHistory.size() > MAX_HISTORY_SIZE) + { + m_deltaHistory.pop_front(); + } + } + + prevTime = currentTime; + m_currentFrame++; + } +} diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h b/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h new file mode 100644 index 000000000..93be55926 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h @@ -0,0 +1,83 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once +#include "pch.h" + +namespace winrt::DynamicRefreshRateTool { + + /** + * Helper for monitoring dcomp refresh rate (fps) and capturing its history. + * Can provide current refresh rate or refresh rate at some previous point in time. + */ + class RefreshRateMeter { + public: + RefreshRateMeter(); + + ~RefreshRateMeter(); + + // Global instance. + static RefreshRateMeter& Instance(); + + // Get current refresh rate. + float GetCurrentRefreshRate() const; + + // Get last frame delta in ticks. + int64_t GetLastFrameDeltaTicks() const; + + // Get timer frequency, or ticks per second. + int64_t GetFrequency() const; + + // Get current tick. + int64_t GetCurrentTick() const; + + // History data point. + struct DataPoint { + // QPC tick - start of the segment. + int64_t tick; + // Number of QPC ticks - duration of the segment. + int64_t deltaTicks; + // Number of frames in the segment. + int64_t framesNumber; + // Average refresh rate in the segment. + float refreshRate; + }; + + std::vector GetRecentHistory(int64_t offsetTicks, int64_t historyLengthTicks, int aggregationSize = 1, int keepEach = 1) const; + + std::vector GetHistoryStartingFrom(int64_t startingFrom) const; + + // Helper that converts refresh rate float value to a readable string. + static std::string RefreshRateToString(float fpsValue); + + private: + void RefreshRateTrackingThread(); + + int64_t m_frequency = 0; + uint64_t m_currentFrame = 0; + + // Up to 10 minutes of history at 60 fps rate + const size_t MAX_HISTORY_SIZE = 60 * 60 * 10; + // List of pairs (start frame QPC tick, frame duration QPC ticks) for the last ~10 minutes + std::deque> m_deltaHistory; + + // Future that owns monitor thread. + std::future m_monitorFuture; + + // Flag to stop the monitor thread. + bool m_shouldStopFpsCalculation = false; + + mutable std::mutex m_mutex; + }; +} \ No newline at end of file diff --git a/Samples/Composition/DynamicRefreshRateTool/app.manifest b/Samples/Composition/DynamicRefreshRateTool/app.manifest new file mode 100644 index 000000000..6988d07bc --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/app.manifest @@ -0,0 +1,15 @@ + + + + + + + + true/PM + PerMonitorV2, PerMonitor + + + diff --git a/Samples/Composition/DynamicRefreshRateTool/packages.config b/Samples/Composition/DynamicRefreshRateTool/packages.config new file mode 100644 index 000000000..a69e1c743 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Samples/Composition/DynamicRefreshRateTool/pch.cpp b/Samples/Composition/DynamicRefreshRateTool/pch.cpp new file mode 100644 index 000000000..17aa0db4f --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/pch.cpp @@ -0,0 +1,15 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#include "pch.h" diff --git a/Samples/Composition/DynamicRefreshRateTool/pch.h b/Samples/Composition/DynamicRefreshRateTool/pch.h new file mode 100644 index 000000000..1e9930d92 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/pch.h @@ -0,0 +1,73 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE SOFTWARE IS PROVIDED ?AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//********************************************************* + +#pragma once +#include +#include +#include +#include + +#include +#pragma comment( lib, "dcomp" ) +#pragma comment( lib, "Dxgi" ) + +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime +#undef GetCurrentTime + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "RefreshRateLogger.h" +#include "RefreshRateMeter.h" + +#include +#include +#include From 60ecbeceb31e39f27aff86427dfb1bb91779d9aa Mon Sep 17 00:00:00 2001 From: Andrii Borziak Date: Wed, 24 Aug 2022 14:17:20 -0700 Subject: [PATCH 2/3] Moved to cpp-winui folder --- .../{ => cpp-winui}/.gitignore | 0 .../{ => cpp-winui}/AnimationPage.cpp | 0 .../{ => cpp-winui}/AnimationPage.h | 0 .../{ => cpp-winui}/AnimationPage.idl | 0 .../{ => cpp-winui}/AnimationPage.xaml | 0 .../DynamicRefreshRateTool/{ => cpp-winui}/App.idl | 0 .../DynamicRefreshRateTool/{ => cpp-winui}/App.xaml | 0 .../{ => cpp-winui}/App.xaml.cpp | 0 .../{ => cpp-winui}/App.xaml.h | 0 .../Assets/LockScreenLogo.scale-200.png | Bin .../Assets/SplashScreen.scale-200.png | Bin .../Assets/Square150x150Logo.scale-200.png | Bin .../Assets/Square44x44Logo.scale-200.png | Bin ...uare44x44Logo.targetsize-24_altform-unplated.png | Bin .../{ => cpp-winui}/Assets/StoreLogo.png | Bin .../Assets/Wide310x150Logo.scale-200.png | Bin .../{ => cpp-winui}/ChartPage.cpp | 0 .../{ => cpp-winui}/ChartPage.h | 0 .../{ => cpp-winui}/ChartPage.idl | 0 .../{ => cpp-winui}/ChartPage.xaml | 0 .../{ => cpp-winui}/DynamicRefreshRateTool.sln | 0 .../{ => cpp-winui}/DynamicRefreshRateTool.vcxproj | 0 .../DynamicRefreshRateTool.vcxproj.filters | 0 .../{ => cpp-winui}/MainWindow.idl | 0 .../{ => cpp-winui}/MainWindow.xaml | 0 .../{ => cpp-winui}/MainWindow.xaml.cpp | 0 .../{ => cpp-winui}/MainWindow.xaml.h | 0 .../{ => cpp-winui}/Package.appxmanifest | 0 .../{ => cpp-winui}/README.md | 0 .../{ => cpp-winui}/RefreshRateLogger.cpp | 0 .../{ => cpp-winui}/RefreshRateLogger.h | 0 .../{ => cpp-winui}/RefreshRateMeter.cpp | 0 .../{ => cpp-winui}/RefreshRateMeter.h | 0 .../{ => cpp-winui}/app.manifest | 0 .../{ => cpp-winui}/packages.config | 0 .../DynamicRefreshRateTool/{ => cpp-winui}/pch.cpp | 0 .../DynamicRefreshRateTool/{ => cpp-winui}/pch.h | 0 37 files changed, 0 insertions(+), 0 deletions(-) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/.gitignore (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/AnimationPage.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/AnimationPage.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/AnimationPage.idl (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/AnimationPage.xaml (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/App.idl (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/App.xaml (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/App.xaml.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/App.xaml.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/LockScreenLogo.scale-200.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/SplashScreen.scale-200.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/Square150x150Logo.scale-200.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/Square44x44Logo.scale-200.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/Square44x44Logo.targetsize-24_altform-unplated.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/StoreLogo.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Assets/Wide310x150Logo.scale-200.png (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/ChartPage.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/ChartPage.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/ChartPage.idl (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/ChartPage.xaml (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/DynamicRefreshRateTool.sln (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/DynamicRefreshRateTool.vcxproj (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/DynamicRefreshRateTool.vcxproj.filters (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/MainWindow.idl (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/MainWindow.xaml (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/MainWindow.xaml.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/MainWindow.xaml.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/Package.appxmanifest (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/README.md (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/RefreshRateLogger.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/RefreshRateLogger.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/RefreshRateMeter.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/RefreshRateMeter.h (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/app.manifest (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/packages.config (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/pch.cpp (100%) rename Samples/Composition/DynamicRefreshRateTool/{ => cpp-winui}/pch.h (100%) diff --git a/Samples/Composition/DynamicRefreshRateTool/.gitignore b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/.gitignore similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/.gitignore rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/.gitignore diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/AnimationPage.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/AnimationPage.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.h diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.idl similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/AnimationPage.idl rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.idl diff --git a/Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.xaml similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/AnimationPage.xaml rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/AnimationPage.xaml diff --git a/Samples/Composition/DynamicRefreshRateTool/App.idl b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.idl similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/App.idl rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.idl diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/App.xaml rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/App.xaml.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/App.xaml.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/App.xaml.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/App.xaml.h diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/LockScreenLogo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/LockScreenLogo.scale-200.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/LockScreenLogo.scale-200.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/LockScreenLogo.scale-200.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/SplashScreen.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/SplashScreen.scale-200.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/SplashScreen.scale-200.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/SplashScreen.scale-200.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square150x150Logo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square150x150Logo.scale-200.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/Square150x150Logo.scale-200.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square150x150Logo.scale-200.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square44x44Logo.scale-200.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.scale-200.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square44x44Logo.scale-200.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square44x44Logo.targetsize-24_altform-unplated.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/Square44x44Logo.targetsize-24_altform-unplated.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Square44x44Logo.targetsize-24_altform-unplated.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/StoreLogo.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/StoreLogo.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/StoreLogo.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/StoreLogo.png diff --git a/Samples/Composition/DynamicRefreshRateTool/Assets/Wide310x150Logo.scale-200.png b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Wide310x150Logo.scale-200.png similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Assets/Wide310x150Logo.scale-200.png rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Assets/Wide310x150Logo.scale-200.png diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/ChartPage.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/ChartPage.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.h diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.idl b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.idl similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/ChartPage.idl rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.idl diff --git a/Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.xaml similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/ChartPage.xaml rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/ChartPage.xaml diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.sln similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.sln rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.sln diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.vcxproj similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.vcxproj diff --git a/Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.vcxproj.filters similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/DynamicRefreshRateTool.vcxproj.filters rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/DynamicRefreshRateTool.vcxproj.filters diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.idl b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.idl similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/MainWindow.idl rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.idl diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/MainWindow.xaml.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/MainWindow.xaml.h diff --git a/Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/Package.appxmanifest similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/Package.appxmanifest rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/Package.appxmanifest diff --git a/Samples/Composition/DynamicRefreshRateTool/README.md b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/README.md similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/README.md rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/README.md diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateLogger.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateLogger.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateLogger.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/RefreshRateLogger.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateLogger.h diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateMeter.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateMeter.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateMeter.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/RefreshRateMeter.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/RefreshRateMeter.h diff --git a/Samples/Composition/DynamicRefreshRateTool/app.manifest b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/app.manifest similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/app.manifest rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/app.manifest diff --git a/Samples/Composition/DynamicRefreshRateTool/packages.config b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/packages.config similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/packages.config rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/packages.config diff --git a/Samples/Composition/DynamicRefreshRateTool/pch.cpp b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/pch.cpp similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/pch.cpp rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/pch.cpp diff --git a/Samples/Composition/DynamicRefreshRateTool/pch.h b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/pch.h similarity index 100% rename from Samples/Composition/DynamicRefreshRateTool/pch.h rename to Samples/Composition/DynamicRefreshRateTool/cpp-winui/pch.h From c93462c4dda51a403b22d971ebe76c45705422fc Mon Sep 17 00:00:00 2001 From: Andrii Borziak Date: Thu, 25 Aug 2022 11:58:07 -0700 Subject: [PATCH 3/3] Added privacy policy --- .../Composition/DynamicRefreshRateTool/cpp-winui/PRIVACY.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Samples/Composition/DynamicRefreshRateTool/cpp-winui/PRIVACY.md diff --git a/Samples/Composition/DynamicRefreshRateTool/cpp-winui/PRIVACY.md b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/PRIVACY.md new file mode 100644 index 000000000..567a70531 --- /dev/null +++ b/Samples/Composition/DynamicRefreshRateTool/cpp-winui/PRIVACY.md @@ -0,0 +1,3 @@ +# Dynamic Refresh Rate Tool Privacy + +The Dynamic Refresh Rate Tool application does not collect, store, or transmit any personal information.