Merge pull request #2359 from stenzek/uwp

Port DuckStation to UWP (and Xbox)
This commit is contained in:
Connor McLaughlin 2021-07-11 15:23:59 +10:00 committed by GitHub
commit 56ef250c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 2958 additions and 125 deletions

4
.gitignore vendored
View File

@ -40,3 +40,7 @@ __pycache__
# other repos
/dep/mac
# UWP crap
Generated Files
/packages

View File

@ -30,15 +30,23 @@
</Link>
</ItemDefinitionGroup>
<!-- Disable exceptions. -->
<ItemDefinitionGroup>
<!-- Disable exceptions when not building for UWP. -->
<ItemDefinitionGroup Condition="'$(BuildingForUWP)'!='true'">
<ClCompile>
<PreprocessorDefinitions>_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>false</ExceptionHandling>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ItemDefinitionGroup Condition="'$(BuildingForUWP)'=='true'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories></AdditionalIncludeDirectories>
<PreprocessorDefinitions>_UWP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugUWP'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -67,7 +75,7 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='ReleaseLTCG'">
<ItemDefinitionGroup Condition="'$(Configuration)'=='ReleaseLTCG' Or '$(Configuration)'=='ReleaseUWP'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>

View File

@ -49,18 +49,59 @@
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugUWP|ARM64">
<Configuration>DebugUWP</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugUWP|Win32">
<Configuration>DebugUWP</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugUWP|x64">
<Configuration>DebugUWP</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseUWP|ARM64">
<Configuration>ReleaseUWP</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseUWP|Win32">
<Configuration>ReleaseUWP</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseUWP|x64">
<Configuration>ReleaseUWP</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="UserMacros">
<BuildingForUWP Condition="'$(Configuration)'=='DebugUWP' Or '$(Configuration)'=='ReleaseUWP'">true</BuildingForUWP>
</PropertyGroup>
<Import Project="$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props" Condition="('$(Configuration)'=='DebugUWP' Or '$(Configuration)'=='ReleaseUWP') And Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<ProjectName>$(MSBuildProjectName)</ProjectName>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="Globals">
<PropertyGroup Label="Globals" Condition="'$(BuildingForUWP)'!='true'">
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Label="Globals" Condition="'$(BuildingForUWP)'=='true'">
<MinimalCoreWin>true</MinimalCoreWin>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == '' ">10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<PropertyGroup Label="UserMacros">
<RootBuildDir>$(SolutionDir)build\$(Configuration)-$(Platform)\</RootBuildDir>
</PropertyGroup>

View File

@ -8,6 +8,12 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<PropertyGroup Label="Globals" Condition="'$(BuildingForUWP)'=='true'">
<CppWinRTOptimized Condition="'$(Configuration)'=='ReleaseUWP'">true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>false</CppWinRTRootNamespaceAutoMerge>
<CppWinRTGenerateWindowsMetadata>false</CppWinRTGenerateWindowsMetadata>
</PropertyGroup>
<Import Project="Toolkit.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -19,4 +25,4 @@
</ItemDefinitionGroup>
<Import Project="Base.props" />
</Project>
</Project>

View File

@ -1,4 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
<Import Project="$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="'$(BuildingForUWP)'=='true' And Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="'$(BuildingForUWP)'=='true' And !Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="'$(BuildingForUWP)'=='true' And !Exists('$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\Microsoft.Windows.CppWinRT.2.0.210505.3\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@ -6,10 +6,10 @@
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast'">
<PropertyGroup Condition="'$(Configuration)'=='Debug' Or '$(Configuration)'=='DebugFast' Or '$(Configuration)'=='DebugUWP'">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG'">
<PropertyGroup Condition="'$(Configuration)'=='Release' Or '$(Configuration)'=='ReleaseLTCG' Or '$(Configuration)'=='ReleaseUWP'">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
</Project>

View File

@ -20,10 +20,12 @@
#endif
// require vista+
#ifndef WINAPI_FAMILY
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif
#include <windows.h>

376
duckstation-uwp.sln Normal file
View File

@ -0,0 +1,376 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.47
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "dep\glad\glad.vcxproj", "{43540154-9E1E-409C-834F-B84BE5621388}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{BA490C0E-497D-4634-A21E-E65012006385}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "dep\imgui\imgui.vcxproj", "{BB08260F-6FBC-46AF-8924-090EE71360C6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common.vcxproj", "{EE054E08-3799-4A59-A422-18259C105FFD}"
ProjectSection(ProjectDependencies) = postProject
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2} = {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}
{43540154-9E1E-409C-834F-B84BE5621388} = {43540154-9E1E-409C-834F-B84BE5621388}
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017} = {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3} = {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxproj", "{868B98C8-65A1-494B-8346-250A73A48C0A}"
ProjectSection(ProjectDependencies) = postProject
{EE054E08-3799-4A59-A422-18259C105FFD} = {EE054E08-3799-4A59-A422-18259C105FFD}
{BB08260F-6FBC-46AF-8924-090EE71360C6} = {BB08260F-6FBC-46AF-8924-090EE71360C6}
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
{09553C96-9F39-49BF-8AE6-7ACBD07C410C} = {09553C96-9F39-49BF-8AE6-7ACBD07C410C}
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stb", "dep\stb\stb.vcxproj", "{ED601289-AC1A-46B8-A8ED-17DB9EB73423}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "dep\simpleini\simpleini.vcxproj", "{3773F4CC-614E-4028-8595-22E08CA649E3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyxml2", "dep\tinyxml2\tinyxml2.vcxproj", "{933118A9-68C5-47B4-B151-B03C93961623}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "dep\minizip\minizip.vcxproj", "{8BDA439C-6358-45FB-9994-2FF083BABE06}"
ProjectSection(ProjectDependencies) = postProject
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "dep\zlib\zlib.vcxproj", "{7FF9FDB9-D504-47DB-A16A-B08071999620}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "dep\libchdr\libchdr.vcxproj", "{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}"
ProjectSection(ProjectDependencies) = postProject
{DD944834-7899-4C1C-A4C1-064B5009D239} = {DD944834-7899-4C1C-A4C1-064B5009D239}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D} = {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC", "dep\libFLAC\libFLAC.vcxproj", "{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzma", "dep\lzma\lzma.vcxproj", "{DD944834-7899-4C1C-A4C1-064B5009D239}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frontend-common", "src\frontend-common\frontend-common.vcxproj", "{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}"
ProjectSection(ProjectDependencies) = postProject
{075CED82-6A20-46DF-94C7-9624AC9DDBEB} = {075CED82-6A20-46DF-94C7-9624AC9DDBEB}
{8BDA439C-6358-45FB-9994-2FF083BABE06} = {8BDA439C-6358-45FB-9994-2FF083BABE06}
{933118A9-68C5-47B4-B151-B03C93961623} = {933118A9-68C5-47B4-B151-B03C93961623}
{868B98C8-65A1-494B-8346-250A73A48C0A} = {868B98C8-65A1-494B-8346-250A73A48C0A}
{3773F4CC-614E-4028-8595-22E08CA649E3} = {3773F4CC-614E-4028-8595-22E08CA649E3}
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "dep\xxhash\xxhash.vcxproj", "{09553C96-9F39-49BF-8AE6-7ACBD07C410C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scmversion", "src\scmversion\scmversion.vcxproj", "{075CED82-6A20-46DF-94C7-9624AC9DDBEB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "dep\glslang\glslang.vcxproj", "{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vulkan-loader", "dep\vulkan-loader\vulkan-loader.vcxproj", "{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vixl", "dep\vixl\vixl.vcxproj", "{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "dep\libsamplerate\libsamplerate.vcxproj", "{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcheevos", "dep\rcheevos\rcheevos.vcxproj", "{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-uwp", "src\duckstation-uwp\duckstation-uwp.vcxproj", "{E2A6CEA9-9537-4C61-B637-81F1F17EF638}"
ProjectSection(ProjectDependencies) = postProject
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6} = {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugUWP|ARM64 = DebugUWP|ARM64
DebugUWP|x64 = DebugUWP|x64
DebugUWP|x86 = DebugUWP|x86
ReleaseUWP|ARM64 = ReleaseUWP|ARM64
ReleaseUWP|x64 = ReleaseUWP|x64
ReleaseUWP|x86 = ReleaseUWP|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x64.Build.0 = DebugUWP|x64
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x64.Build.0 = DebugUWP|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x64.Build.0 = DebugUWP|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x64.Build.0 = DebugUWP|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x64.Build.0 = DebugUWP|x64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x64.Build.0 = DebugUWP|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x64.Build.0 = DebugUWP|x64
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x64.Build.0 = DebugUWP|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x64.Build.0 = DebugUWP|x64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x64.Build.0 = DebugUWP|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x64.Build.0 = DebugUWP|x64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x64.Build.0 = DebugUWP|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x64.Build.0 = DebugUWP|x64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x64.Build.0 = DebugUWP|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x64.Build.0 = DebugUWP|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x64.Build.0 = DebugUWP|x64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x64.Build.0 = DebugUWP|x64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x64.Build.0 = DebugUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x64.Build.0 = DebugUWP|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.Deploy.0 = DebugUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.Build.0 = DebugUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.Deploy.0 = DebugUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.Build.0 = DebugUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.Deploy.0 = DebugUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.Deploy.0 = ReleaseUWP|ARM64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.Deploy.0 = ReleaseUWP|x64
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
{E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.Deploy.0 = ReleaseUWP|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{43540154-9E1E-409C-834F-B84BE5621388} = {BA490C0E-497D-4634-A21E-E65012006385}
{BB08260F-6FBC-46AF-8924-090EE71360C6} = {BA490C0E-497D-4634-A21E-E65012006385}
{ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {BA490C0E-497D-4634-A21E-E65012006385}
{3773F4CC-614E-4028-8595-22E08CA649E3} = {BA490C0E-497D-4634-A21E-E65012006385}
{933118A9-68C5-47B4-B151-B03C93961623} = {BA490C0E-497D-4634-A21E-E65012006385}
{8BDA439C-6358-45FB-9994-2FF083BABE06} = {BA490C0E-497D-4634-A21E-E65012006385}
{7FF9FDB9-D504-47DB-A16A-B08071999620} = {BA490C0E-497D-4634-A21E-E65012006385}
{425D6C99-D1C8-43C2-B8AC-4D7B1D941017} = {BA490C0E-497D-4634-A21E-E65012006385}
{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D} = {BA490C0E-497D-4634-A21E-E65012006385}
{DD944834-7899-4C1C-A4C1-064B5009D239} = {BA490C0E-497D-4634-A21E-E65012006385}
{09553C96-9F39-49BF-8AE6-7ACBD07C410C} = {BA490C0E-497D-4634-A21E-E65012006385}
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2} = {BA490C0E-497D-4634-A21E-E65012006385}
{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {BA490C0E-497D-4634-A21E-E65012006385}
{8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {BA490C0E-497D-4634-A21E-E65012006385}
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3} = {BA490C0E-497D-4634-A21E-E65012006385}
{4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {BA490C0E-497D-4634-A21E-E65012006385}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {26E40B32-7C1D-48D0-95F4-1A500E054028}
EndGlobalSection
EndGlobal

View File

@ -3,7 +3,7 @@
#include <cstdlib>
#include <mutex>
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
#include "windows_headers.h"
#include <intrin.h>
#include <tlhelp32.h>
@ -13,7 +13,7 @@ static std::mutex s_AssertFailedMutex;
static inline void FreezeThreads(void** ppHandle)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
@ -43,7 +43,7 @@ static inline void FreezeThreads(void** ppHandle)
static inline void ResumeThreads(void* pHandle)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
HANDLE hSnapshot = (HANDLE)pHandle;
if (pHandle != INVALID_HANDLE_VALUE)
{
@ -79,7 +79,7 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char*
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)", szMessage, szFunction, szFile, uLine);
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);
@ -114,7 +114,7 @@ void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char*
char szMsg[512];
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)", szMessage, szFunction, szFile, uLine);
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
OutputDebugStringA(szMsg);

View File

@ -884,7 +884,7 @@ std::unique_ptr<ByteStream> ByteStream_OpenFileStream(const char* fileName, u32
if ((openMode & (BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE)) == BYTESTREAM_OPEN_WRITE)
{
// if opening with write but not create, the path must exist.
if (GetFileAttributes(fileName) == INVALID_FILE_ATTRIBUTES)
if (!FileSystem::FileExists(fileName))
return nullptr;
}
@ -895,7 +895,7 @@ std::unique_ptr<ByteStream> ByteStream_OpenFileStream(const char* fileName, u32
{
// if the file exists, use r+, otherwise w+
// HACK: if we're not truncating, and the file exists (we want to only update it), we still have to use r+
if ((openMode & BYTESTREAM_OPEN_TRUNCATE) || GetFileAttributes(fileName) == INVALID_FILE_ATTRIBUTES)
if (!FileSystem::FileExists(fileName))
{
modeString[modeStringLength++] = 'w';
if (openMode & BYTESTREAM_OPEN_READ)
@ -1013,8 +1013,15 @@ std::unique_ptr<ByteStream> ByteStream_OpenFileStream(const char* fileName, u32
DWORD desiredAccess = GENERIC_WRITE;
if (openMode & BYTESTREAM_OPEN_READ)
desiredAccess |= GENERIC_READ;
#ifndef _UWP
HANDLE hFile =
CreateFileW(wideTemporaryFileName.c_str(), desiredAccess, FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, NULL);
#else
HANDLE hFile =
CreateFile2FromAppW(wideTemporaryFileName.c_str(), desiredAccess, FILE_SHARE_DELETE, CREATE_NEW, nullptr);
#endif
if (hFile == INVALID_HANDLE_VALUE)
return nullptr;
@ -1175,8 +1182,8 @@ std::unique_ptr<ByteStream> ByteStream_OpenFileStream(const char* fileName, u32
}
else // if (errno == ENOTDIR)
{
// well.. someone's trying to open a fucking weird path that is comprised of both directories and files...
// I aint sticking around here to find out what disaster awaits... let fopen deal with it
// well.. someone's trying to open a fucking weird path that is comprised of both directories and
// files... I aint sticking around here to find out what disaster awaits... let fopen deal with it
break;
}
}

View File

@ -33,8 +33,7 @@
<ClInclude Include="file_system.h" />
<ClInclude Include="gl\context.h" />
<ClInclude Include="gl\context_wgl.h">
<ExcludedFromBuild Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)'=='DebugUWP' Or '$(Configuration)'=='ReleaseUWP'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64' Or '$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="gl\program.h" />
<ClInclude Include="gl\shader_cache.h" />
@ -62,7 +61,9 @@
<ClInclude Include="state_wrapper.h" />
<ClInclude Include="string.h" />
<ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\StackWalker.h" />
<ClInclude Include="thirdparty\StackWalker.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="timer.h" />
<ClInclude Include="timestamp.h" />
<ClInclude Include="types.h" />
@ -79,7 +80,9 @@
<ClInclude Include="vulkan\texture.h" />
<ClInclude Include="vulkan\util.h" />
<ClInclude Include="wav_writer.h" />
<ClInclude Include="win32_progress_callback.h" />
<ClInclude Include="win32_progress_callback.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="window_info.h" />
</ItemGroup>
<ItemGroup>
@ -116,8 +119,7 @@
<ClCompile Include="file_system.cpp" />
<ClCompile Include="gl\context.cpp" />
<ClCompile Include="gl\context_wgl.cpp">
<ExcludedFromBuild Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)'=='DebugUWP' Or '$(Configuration)'=='ReleaseUWP'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64' Or '$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="gl\program.cpp" />
<ClCompile Include="gl\shader_cache.cpp" />
@ -140,7 +142,7 @@
<ClCompile Include="string.cpp" />
<ClCompile Include="string_util.cpp" />
<ClCompile Include="thirdparty\StackWalker.cpp">
<ExcludedFromBuild Condition="'$(Configuration)'=='DebugUWP' Or '$(Configuration)'=='ReleaseUWP'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="timer.cpp" />
<ClCompile Include="timestamp.cpp" />
@ -155,7 +157,9 @@
<ClCompile Include="vulkan\texture.cpp" />
<ClCompile Include="vulkan\util.cpp" />
<ClCompile Include="wav_writer.cpp" />
<ClCompile Include="win32_progress_callback.cpp" />
<ClCompile Include="win32_progress_callback.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="window_info.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,7 @@
#include <cinttypes>
#include <cstdio>
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
#include "windows_headers.h"
#include "thirdparty/StackWalker.h"

View File

@ -21,6 +21,20 @@
#if defined(_WIN32)
#include <shlobj.h>
#if defined(_UWP)
#include <fcntl.h>
#include <io.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.FileProperties.h>
#include <winrt/Windows.Storage.Search.h>
#include <winrt/Windows.Storage.h>
#endif
#else
#include <dirent.h>
#include <errno.h>
@ -713,7 +727,7 @@ std::vector<std::string> GetRootDirectoryList()
{
std::vector<std::string> results;
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
char buf[256];
if (GetLogicalDriveStringsA(sizeof(buf), buf) != 0)
{
@ -725,6 +739,28 @@ std::vector<std::string> GetRootDirectoryList()
ptr += len + 1u;
}
}
#elif defined(_UWP)
if (const auto install_location = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
install_location)
{
if (const auto path = install_location.Path(); !path.empty())
results.push_back(StringUtil::WideStringToUTF8String(path));
}
if (const auto local_location = winrt::Windows::Storage::ApplicationData::Current().LocalFolder(); local_location)
{
if (const auto path = local_location.Path(); !path.empty())
results.push_back(StringUtil::WideStringToUTF8String(path));
}
const auto devices = winrt::Windows::Storage::KnownFolders::RemovableDevices();
const auto folders_task(devices.GetFoldersAsync());
for (const auto& storage_folder : folders_task.get())
{
const auto path = storage_folder.Path();
if (!path.empty())
results.push_back(StringUtil::WideStringToUTF8String(path));
}
#else
const char* home_path = std::getenv("HOME");
if (home_path)
@ -772,6 +808,106 @@ FileSystem::ManagedCFilePtr OpenManagedCFile(const char* filename, const char* m
return ManagedCFilePtr(OpenCFile(filename, mode), [](std::FILE* fp) { std::fclose(fp); });
}
#ifdef _UWP
std::FILE* OpenCFileUWP(const wchar_t* wfilename, const wchar_t* mode)
{
DWORD access = 0;
DWORD share = 0;
DWORD disposition = 0;
int flags = 0;
const wchar_t* tmode = mode;
while (*tmode)
{
if (*tmode == L'r' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = OPEN_EXISTING;
flags |= _O_RDWR;
tmode += 2;
}
else if (*tmode == L'w' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_RDWR | _O_CREAT | _O_TRUNC;
tmode += 2;
}
else if (*tmode == L'a' && *(tmode + 1) == L'+')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC;
tmode += 2;
}
else if (*tmode == L'r')
{
access = GENERIC_READ;
share = 0;
disposition = OPEN_EXISTING;
flags |= _O_RDONLY;
tmode++;
}
else if (*tmode == L'w')
{
access = GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_WRONLY | _O_CREAT | _O_TRUNC;
tmode++;
}
else if (*tmode == L'a')
{
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disposition = CREATE_ALWAYS;
flags |= _O_WRONLY | _O_APPEND | _O_CREAT | _O_TRUNC;
tmode++;
}
else if (*tmode == L'b')
{
flags |= _O_BINARY;
tmode++;
}
else
{
Log_ErrorPrintf("Unknown mode flags: '%s'", StringUtil::WideStringToUTF8String(mode).c_str());
return nullptr;
}
}
HANDLE hFile = CreateFileFromAppW(wfilename, access, share, nullptr, disposition, 0, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return nullptr;
if (flags & _O_APPEND && !SetFilePointerEx(hFile, LARGE_INTEGER{}, nullptr, FILE_END))
{
Log_ErrorPrintf("SetFilePointerEx() failed: %08X", GetLastError());
CloseHandle(hFile);
return nullptr;
}
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(hFile), flags);
if (fd < 0)
{
CloseHandle(hFile);
return nullptr;
}
std::FILE* fp = _wfdopen(fd, mode);
if (!fp)
{
_close(fd);
return nullptr;
}
return fp;
}
#endif // _UWP
std::FILE* OpenCFile(const char* filename, const char* mode)
{
#ifdef _WIN32
@ -789,9 +925,16 @@ std::FILE* OpenCFile(const char* filename, const char* mode)
{
wfilename[wlen] = 0;
wmode[wmodelen] = 0;
std::FILE* fp;
if (_wfopen_s(&fp, wfilename, wmode) != 0)
{
#ifdef _UWP
return OpenCFileUWP(wfilename, wmode);
#else
return nullptr;
#endif
}
return fp;
}
@ -1052,6 +1195,19 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
return r;
}
static DWORD WrapGetFileAttributes(const wchar_t* path)
{
#ifndef _UWP
return GetFileAttributesW(path);
#else
WIN32_FILE_ATTRIBUTE_DATA fad;
if (!GetFileAttributesExFromAppW(path, GetFileExInfoStandard, &fad))
return INVALID_FILE_ATTRIBUTES;
return fad.dwFileAttributes;
#endif
}
static const u32 READ_DIRECTORY_CHANGES_NOTIFY_FILTER = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION;
@ -1064,7 +1220,7 @@ public:
m_directoryChangeQueued(false)
{
m_bufferSize = 16384;
m_pBuffer = new byte[m_bufferSize];
m_pBuffer = new u8[m_bufferSize];
}
virtual ~ChangeNotifierWin32()
@ -1103,7 +1259,7 @@ public:
// has any bytes?
if (bytesRead > 0)
{
const byte* pCurrentPointer = m_pBuffer;
const u8* pCurrentPointer = m_pBuffer;
PathString fileName;
for (;;)
{
@ -1176,15 +1332,26 @@ private:
HANDLE m_hDirectory;
OVERLAPPED m_overlapped;
bool m_directoryChangeQueued;
byte* m_pBuffer;
u8* m_pBuffer;
u32 m_bufferSize;
};
std::unique_ptr<ChangeNotifier> CreateChangeNotifier(const char* path, bool recursiveWatch)
{
// open the directory up
HANDLE hDirectory = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
std::wstring path_wstr(StringUtil::UTF8StringToWideString(path));
#ifndef _UWP
HANDLE hDirectory =
CreateFileW(path_wstr.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
#else
CREATEFILE2_EXTENDED_PARAMETERS ep = {};
ep.dwSize = sizeof(ep);
ep.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
ep.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
HANDLE hDirectory = CreateFile2FromAppW(path_wstr.c_str(), FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, OPEN_EXISTING, &ep);
#endif
if (hDirectory == nullptr)
return nullptr;
@ -1212,8 +1379,18 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
tempStr = StringUtil::StdStringFromFormat("%s\\*", OriginPath);
}
// holder for utf-8 conversion
WIN32_FIND_DATAW wfd;
std::string utf8_filename;
utf8_filename.reserve(countof(wfd.cFileName) * 2);
#ifndef _UWP
HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
#else
HANDLE hFind = FindFirstFileExFromAppW(StringUtil::UTF8StringToWideString(tempStr).c_str(), FindExInfoBasic, &wfd,
FindExSearchNameMatch, nullptr, 0);
#endif
if (hFind == INVALID_HANDLE_VALUE)
return 0;
@ -1227,10 +1404,6 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
wildCardMatchAll = !(std::strcmp(Pattern, "*"));
}
// holder for utf-8 conversion
std::string utf8_filename;
utf8_filename.reserve(countof(wfd.cFileName) * 2);
// iterate results
do
{
@ -1360,6 +1533,7 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
wpath[wlen] = 0;
#ifndef _UWP
// determine attributes for the path. if it's a directory, things have to be handled differently..
DWORD fileAttributes = GetFileAttributesW(wpath);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
@ -1398,6 +1572,16 @@ bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
pStatData->ModificationTime.SetWindowsFileTime(&bhfi.ftLastWriteTime);
pStatData->Size = ((u64)bhfi.nFileSizeHigh) << 32 | (u64)bhfi.nFileSizeLow;
return true;
#else
WIN32_FILE_ATTRIBUTE_DATA fad;
if (!GetFileAttributesExFromAppW(wpath, GetFileExInfoStandard, &fad))
return false;
pStatData->Attributes = TranslateWin32Attributes(fad.dwFileAttributes);
pStatData->ModificationTime.SetWindowsFileTime(&fad.ftLastWriteTime);
pStatData->Size = ((u64)fad.nFileSizeHigh) << 32 | (u64)fad.nFileSizeLow;
return true;
#endif
}
bool FileSystem::StatFile(std::FILE* fp, FILESYSTEM_STAT_DATA* pStatData)
@ -1447,7 +1631,7 @@ bool FileSystem::FileExists(const char* path)
wpath[wlen] = 0;
// determine attributes for the path. if it's a directory, things have to be handled differently..
DWORD fileAttributes = GetFileAttributesW(wpath);
DWORD fileAttributes = WrapGetFileAttributes(wpath);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
@ -1477,7 +1661,7 @@ bool FileSystem::DirectoryExists(const char* path)
wpath[wlen] = 0;
// determine attributes for the path. if it's a directory, things have to be handled differently..
DWORD fileAttributes = GetFileAttributesW(wpath);
DWORD fileAttributes = WrapGetFileAttributes(wpath);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
@ -1495,16 +1679,21 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
if (wpath[0] == L'\0')
return false;
// try just flat-out, might work if there's no other segments that have to be made
// try just flat-out, might work if there's no other segments that have to be made
#ifndef _UWP
if (CreateDirectoryW(wpath.c_str(), nullptr))
return true;
#else
if (CreateDirectoryFromAppW(wpath.c_str(), nullptr))
return true;
#endif
// check error
DWORD lastError = GetLastError();
if (lastError == ERROR_ALREADY_EXISTS)
{
// check the attributes
u32 Attributes = GetFileAttributesW(wpath.c_str());
u32 Attributes = WrapGetFileAttributes(wpath.c_str());
if (Attributes != INVALID_FILE_ATTRIBUTES && Attributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
else
@ -1523,7 +1712,13 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
if (wpath[i] == L'\\' || wpath[i] == L'/')
{
tempStr[i] = L'\0';
if (!CreateDirectoryW(tempStr, nullptr))
#ifndef _UWP
const BOOL result = CreateDirectoryW(tempStr, nullptr);
#else
const BOOL result = CreateDirectoryFromAppW(tempStr, nullptr);
#endif
if (!result)
{
lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS) // fine, continue to next path segment
@ -1537,7 +1732,12 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
// re-create the end if it's not a separator, check / as well because windows can interpret them
if (wpath[pathLength - 1] != L'\\' && wpath[pathLength - 1] != L'/')
{
if (!CreateDirectoryW(wpath.c_str(), nullptr))
#ifndef _UWP
const BOOL result = CreateDirectoryW(wpath.c_str(), nullptr);
#else
const BOOL result = CreateDirectoryFromAppW(wpath.c_str(), nullptr);
#endif
if (!result)
{
lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS)
@ -1561,14 +1761,15 @@ bool FileSystem::DeleteFile(const char* Path)
return false;
const std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
const DWORD fileAttributes = WrapGetFileAttributes(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES || fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
return (DeleteFileW(wpath.c_str()) == TRUE);
else
return false;
#ifndef _UWP
return (DeleteFileW(wpath.c_str()) == TRUE);
#else
return (DeleteFileFromAppW(wpath.c_str()) == TRUE);
#endif
}
bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
@ -1576,11 +1777,19 @@ bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
const std::wstring old_wpath(StringUtil::UTF8StringToWideString(OldPath));
const std::wstring new_wpath(StringUtil::UTF8StringToWideString(NewPath));
#ifndef _UWP
if (!MoveFileExW(old_wpath.c_str(), new_wpath.c_str(), MOVEFILE_REPLACE_EXISTING))
{
Log_ErrorPrintf("MoveFileEx('%s', '%s') failed: %08X", OldPath, NewPath, GetLastError());
return false;
}
#else
if (!ReplaceFileFromAppW(old_wpath.c_str(), new_wpath.c_str(), nullptr, 0, nullptr, nullptr))
{
Log_ErrorPrintf("MoveFileFromAppW('%s', '%s') failed: %08X", OldPath, NewPath, GetLastError());
return false;
}
#endif
return true;
}
@ -1588,13 +1797,19 @@ bool FileSystem::RenamePath(const char* OldPath, const char* NewPath)
static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
{
// ensure it exists
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES || !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
const DWORD fileAttributes = WrapGetFileAttributes(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES || fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
// non-recursive case just try removing the directory
if (!Recursive)
{
#ifndef _UWP
return (RemoveDirectoryW(wpath.c_str()) == TRUE);
#else
return (RemoveDirectoryFromAppW(wpath.c_str()) == TRUE);
#endif
}
// doing a recursive delete
std::wstring fileName = wpath;
@ -1602,7 +1817,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
// is there any files?
WIN32_FIND_DATAW findData;
#ifndef _UWP
HANDLE hFind = FindFirstFileW(fileName.c_str(), &findData);
#else
HANDLE hFind =
FindFirstFileExFromAppW(fileName.c_str(), FindExInfoBasic, &findData, FindExSearchNameMatch, nullptr, 0);
#endif
if (hFind == INVALID_HANDLE_VALUE)
return false;
@ -1634,7 +1854,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
else
{
// found a file, so delete it
if (!DeleteFileW(fileName.c_str()))
#ifndef _UWP
const BOOL result = DeleteFileW(fileName.c_str());
#else
const BOOL result = DeleteFileFromAppW(fileName.c_str());
#endif
if (!result)
{
FindClose(hFind);
return false;
@ -1644,7 +1869,12 @@ static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
FindClose(hFind);
// nuke the directory itself
if (!RemoveDirectoryW(wpath.c_str()))
#ifndef _UWP
const BOOL result = RemoveDirectoryW(wpath.c_str());
#else
const BOOL result = RemoveDirectoryFromAppW(wpath.c_str());
#endif
if (!result)
return false;
// done
@ -1664,8 +1894,10 @@ std::string GetProgramPath()
// Fall back to the main module if this fails.
HMODULE module = nullptr;
#ifndef _UWP
GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&GetProgramPath), &module);
#endif
for (;;)
{

View File

@ -44,7 +44,21 @@ bool JitCodeBuffer::Allocate(u32 size /* = 64 * 1024 * 1024 */, u32 far_code_siz
m_total_size = size + far_code_size;
#if defined(_WIN32)
#if !defined(_UWP)
m_code_ptr = static_cast<u8*>(VirtualAlloc(nullptr, m_total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE));
#else
m_code_ptr = static_cast<u8*>(
VirtualAlloc2FromApp(GetCurrentProcess(), nullptr, m_total_size, MEM_COMMIT, PAGE_READWRITE, nullptr, 0));
if (m_code_ptr)
{
ULONG old_protection;
if (!VirtualProtectFromApp(m_code_ptr, m_total_size, PAGE_EXECUTE_READWRITE, &old_protection))
{
VirtualFree(m_code_ptr, m_total_size, MEM_RELEASE);
return false;
}
}
#endif
if (!m_code_ptr)
{
Log_ErrorPrintf("VirtualAlloc(RWX, %u) for internal buffer failed: %u", m_total_size, GetLastError());
@ -157,20 +171,48 @@ void JitCodeBuffer::Destroy()
if (m_owns_buffer)
{
#if defined(_WIN32)
VirtualFree(m_code_ptr, 0, MEM_RELEASE);
if (!VirtualFree(m_code_ptr, 0, MEM_RELEASE))
Log_ErrorPrintf("Failed to free code pointer %p", m_code_ptr);
#elif defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) || defined(__HAIKU__) || defined(__FreeBSD__)
munmap(m_code_ptr, m_total_size);
if (munmap(m_code_ptr, m_total_size) != 0)
Log_ErrorPrintf("Failed to free code pointer %p", m_code_ptr);
#endif
}
else if (m_code_ptr)
{
#if defined(_WIN32)
DWORD old_protect = 0;
VirtualProtect(m_code_ptr, m_total_size, m_old_protection, &old_protect);
if (!VirtualProtect(m_code_ptr, m_total_size, m_old_protection, &old_protect))
Log_ErrorPrintf("Failed to restore protection on %p", m_code_ptr);
#else
mprotect(m_code_ptr, m_total_size, m_old_protection);
if (mprotect(m_code_ptr, m_total_size, m_old_protection) != 0)
Log_ErrorPrintf("Failed to restore protection on %p", m_code_ptr);
#endif
}
m_code_ptr = nullptr;
m_free_code_ptr = nullptr;
m_code_size = 0;
m_code_reserve_size = 0;
m_code_used = 0;
m_far_code_ptr = nullptr;
m_free_far_code_ptr = nullptr;
m_far_code_size = 0;
m_far_code_used = 0;
m_total_size = 0;
m_guard_size = 0;
m_old_protection = 0;
m_owns_buffer = false;
}
void JitCodeBuffer::ReserveCode(u32 size)
{
Assert(m_code_used == 0);
Assert(size < m_code_size);
m_code_reserve_size += size;
m_free_code_ptr += size;
m_code_size -= size;
}
void JitCodeBuffer::CommitCode(u32 length)
@ -207,7 +249,7 @@ void JitCodeBuffer::Reset()
{
WriteProtect(false);
m_free_code_ptr = m_code_ptr + m_guard_size;
m_free_code_ptr = m_code_ptr + m_guard_size + m_code_reserve_size;
m_code_used = 0;
std::memset(m_free_code_ptr, 0, m_code_size);
FlushInstructionCache(m_free_code_ptr, m_code_size);

View File

@ -9,20 +9,23 @@ public:
JitCodeBuffer(void* buffer, u32 size, u32 far_code_size, u32 guard_size);
~JitCodeBuffer();
bool IsValid() const { return (m_code_ptr != nullptr); }
bool Allocate(u32 size = 64 * 1024 * 1024, u32 far_code_size = 0);
bool Initialize(void* buffer, u32 size, u32 far_code_size = 0, u32 guard_size = 0);
void Destroy();
void Reset();
u8* GetCodePointer() const { return m_code_ptr; }
u32 GetTotalSize() const { return m_total_size; }
ALWAYS_INLINE u8* GetCodePointer() const { return m_code_ptr; }
ALWAYS_INLINE u32 GetTotalSize() const { return m_total_size; }
u8* GetFreeCodePointer() const { return m_free_code_ptr; }
u32 GetFreeCodeSpace() const { return static_cast<u32>(m_code_size - m_code_used); }
ALWAYS_INLINE u8* GetFreeCodePointer() const { return m_free_code_ptr; }
ALWAYS_INLINE u32 GetFreeCodeSpace() const { return static_cast<u32>(m_code_size - m_code_used); }
void ReserveCode(u32 size);
void CommitCode(u32 length);
u8* GetFreeFarCodePointer() const { return m_free_far_code_ptr; }
u32 GetFreeFarCodeSpace() const { return static_cast<u32>(m_far_code_size - m_far_code_used); }
ALWAYS_INLINE u8* GetFreeFarCodePointer() const { return m_free_far_code_ptr; }
ALWAYS_INLINE u32 GetFreeFarCodeSpace() const { return static_cast<u32>(m_far_code_size - m_far_code_used); }
void CommitFarCode(u32 length);
/// Adjusts the free code pointer to the specified alignment, padding with bytes.
@ -43,6 +46,7 @@ private:
u8* m_code_ptr = nullptr;
u8* m_free_code_ptr = nullptr;
u32 m_code_size = 0;
u32 m_code_reserve_size = 0;
u32 m_code_used = 0;
u8* m_far_code_ptr = nullptr;

View File

@ -135,8 +135,13 @@ bool MemoryArena::Create(size_t size, bool writable, bool executable)
#if defined(_WIN32)
const DWORD protect = (writable ? (executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE) : PAGE_READONLY);
#ifndef _UWP
m_file_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, protect, Truncate32(size >> 32), Truncate32(size),
file_mapping_name.c_str());
#else
m_file_handle = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, nullptr, protect, size,
StringUtil::UTF8StringToWideString(file_mapping_name).c_str());
#endif
if (!m_file_handle)
{
Log_ErrorPrintf("CreateFileMapping failed: %u", GetLastError());
@ -257,8 +262,16 @@ void* MemoryArena::CreateViewPtr(size_t offset, size_t size, bool writable, bool
void* base_pointer;
#if defined(_WIN32)
const DWORD desired_access = FILE_MAP_READ | (writable ? FILE_MAP_WRITE : 0) | (executable ? FILE_MAP_EXECUTE : 0);
#ifndef _UWP
base_pointer =
MapViewOfFileEx(m_file_handle, desired_access, Truncate32(offset >> 32), Truncate32(offset), size, fixed_address);
#else
// UWP does not support fixed mappings.
if (!fixed_address)
base_pointer = MapViewOfFileFromApp(m_file_handle, desired_access, offset, size);
else
base_pointer = nullptr;
#endif
if (!base_pointer)
return nullptr;
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)

View File

@ -24,8 +24,10 @@ namespace Common::PageFaultHandler {
struct RegisteredHandler
{
void* owner;
Callback callback;
const void* owner;
void* start_pc;
u32 code_size;
};
static std::vector<RegisteredHandler> m_handlers;
static std::mutex m_handler_lock;
@ -78,7 +80,7 @@ static bool IsStoreInstruction(const void* ptr)
}
#endif
#if defined(_WIN32) && (defined(CPU_X64) || defined(CPU_AARCH64))
#if defined(_WIN32) && !defined(_UWP) && (defined(CPU_X64) || defined(CPU_AARCH64))
static PVOID s_veh_handle;
static LONG ExceptionHandler(PEXCEPTION_POINTERS exi)
@ -110,9 +112,149 @@ static LONG ExceptionHandler(PEXCEPTION_POINTERS exi)
}
s_in_handler = false;
return EXCEPTION_CONTINUE_SEARCH;
}
u32 GetHandlerCodeSize()
{
return 0;
}
#elif defined(_UWP)
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160
struct UNWIND_INFO
{
BYTE version : 3;
BYTE flags : 5;
BYTE size_of_prologue;
BYTE count_of_unwind_codes;
BYTE frame_register : 4;
BYTE frame_offset_scaled : 4;
ULONG exception_handler_address;
};
struct UnwindHandler
{
RUNTIME_FUNCTION runtime_function;
UNWIND_INFO unwind_info;
uint8_t exception_handler_code[32];
};
static constexpr size_t UNWIND_HANDLER_ALLOC_SIZE = 4096;
static_assert(sizeof(UnwindHandler) <= UNWIND_HANDLER_ALLOC_SIZE);
static EXCEPTION_DISPOSITION UnwindExceptionHandler(PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame,
PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext)
{
if (s_in_handler)
return ExceptionContinueSearch;
s_in_handler = true;
void* const exception_pc = reinterpret_cast<void*>(DispatcherContext->ControlPc);
void* const exception_address = reinterpret_cast<void*>(ExceptionRecord->ExceptionInformation[1]);
bool const is_write = ExceptionRecord->ExceptionInformation[0] == 1;
std::lock_guard<std::mutex> guard(m_handler_lock);
for (const RegisteredHandler& rh : m_handlers)
{
if (static_cast<const u8*>(exception_pc) >= static_cast<const u8*>(rh.start_pc) &&
static_cast<const u8*>(exception_pc) <= (static_cast<const u8*>(rh.start_pc) + rh.code_size))
{
if (rh.callback(exception_pc, exception_address, is_write) == HandlerResult::ContinueExecution)
{
s_in_handler = false;
return ExceptionContinueExecution;
}
}
}
s_in_handler = false;
return ExceptionContinueSearch;
}
static PRUNTIME_FUNCTION GetRuntimeFunctionCallback(DWORD64 ControlPc, PVOID Context)
{
std::lock_guard<std::mutex> guard(m_handler_lock);
for (const RegisteredHandler& rh : m_handlers)
{
if (ControlPc >= reinterpret_cast<DWORD64>(rh.start_pc) &&
ControlPc <= (reinterpret_cast<DWORD64>(rh.start_pc) + rh.code_size))
{
return reinterpret_cast<PRUNTIME_FUNCTION>(rh.start_pc);
}
}
return nullptr;
}
static bool InstallFunctionTableCallback(const void* owner, void* start_pc, u32 code_size)
{
if (code_size < UNWIND_HANDLER_ALLOC_SIZE)
{
Log_ErrorPrintf("Invalid code size: %u @ %p", code_size, UNWIND_HANDLER_ALLOC_SIZE);
return false;
}
if (!RtlInstallFunctionTableCallback(reinterpret_cast<DWORD64>(owner) | 0x3, reinterpret_cast<DWORD64>(start_pc),
static_cast<DWORD>(code_size), &GetRuntimeFunctionCallback, nullptr, nullptr))
{
Log_ErrorPrintf("RtlInstallFunctionTableCallback() failed: %08X", GetLastError());
return false;
}
// This is only valid on x86 for now.
#ifndef CPU_X64
Log_ErrorPrint("Exception unwind codegen not implemented");
return false;
#else
UnwindHandler* uh = static_cast<UnwindHandler*>(start_pc);
ULONG old_protection;
if (!VirtualProtectFromApp(uh, UNWIND_HANDLER_ALLOC_SIZE, PAGE_READWRITE, &old_protection))
{
Log_ErrorPrintf("VirtualProtectFromApp(RW) for exception handler failed: %08X", GetLastError());
return false;
}
uh->runtime_function.BeginAddress = UNWIND_HANDLER_ALLOC_SIZE;
uh->runtime_function.EndAddress = code_size;
uh->runtime_function.UnwindInfoAddress = offsetof(UnwindHandler, unwind_info);
uh->unwind_info.version = 1;
uh->unwind_info.flags = UNW_FLAG_EHANDLER;
uh->unwind_info.size_of_prologue = 0;
uh->unwind_info.count_of_unwind_codes = 0;
uh->unwind_info.frame_register = 0;
uh->unwind_info.frame_offset_scaled = 0;
uh->unwind_info.exception_handler_address = offsetof(UnwindHandler, exception_handler_code);
// mov rax, handler
const void* handler = UnwindExceptionHandler;
uh->exception_handler_code[0] = 0x48;
uh->exception_handler_code[1] = 0xb8;
std::memcpy(&uh->exception_handler_code[2], &handler, sizeof(handler));
// jmp rax
uh->exception_handler_code[10] = 0xff;
uh->exception_handler_code[11] = 0xe0;
if (!VirtualProtectFromApp(uh, UNWIND_HANDLER_ALLOC_SIZE, PAGE_EXECUTE_READ, &old_protection))
{
Log_ErrorPrintf("VirtualProtectFromApp(RX) for exception handler failed: %08X", GetLastError());
return false;
}
return true;
#endif
}
u32 GetHandlerCodeSize()
{
return UNWIND_HANDLER_ALLOC_SIZE;
}
#elif defined(USE_SIGSEGV)
static struct sigaction s_old_sigsegv_action;
@ -203,9 +345,21 @@ static void SIGSEGVHandler(int sig, siginfo_t* info, void* ctx)
sa.sa_handler(sig);
}
u32 GetHandlerCodeSize()
{
return 0;
}
#else
u32 GetHandlerCodeSize()
{
return 0;
}
#endif
bool InstallHandler(void* owner, Callback callback)
bool InstallHandler(const void* owner, void* start_pc, u32 code_size, Callback callback)
{
bool was_empty;
{
@ -217,31 +371,24 @@ bool InstallHandler(void* owner, Callback callback)
}
was_empty = m_handlers.empty();
m_handlers.push_back(RegisteredHandler{owner, std::move(callback)});
}
if (was_empty)
{
#if defined(_WIN32) && (defined(CPU_X64) || defined(CPU_AARCH64))
#if defined(_WIN32) && !defined(_UWP) && (defined(CPU_X64) || defined(CPU_AARCH64))
s_veh_handle = AddVectoredExceptionHandler(1, ExceptionHandler);
if (!s_veh_handle)
{
Log_ErrorPrint("Failed to add vectored exception handler");
return false;
}
#elif defined(USE_SIGSEGV)
#if 0
// Alternative stack - we'll need this is we ever use the host stack for branches.
stack_t signal_stack = {};
signal_stack.ss_sp = malloc(SIGSTKSZ);
signal_stack.ss_size = SIGSTKSZ;
if (sigaltstack(&signal_stack, nullptr))
#elif defined(_UWP)
if (!InstallFunctionTableCallback(owner, start_pc, code_size))
{
Log_ErrorPrintf("signaltstack() failed: %d", errno);
Log_ErrorPrint("Failed to install function table callback");
return false;
}
#endif
#elif defined(USE_SIGSEGV)
struct sigaction sa = {};
sa.sa_sigaction = SIGSEGVHandler;
sa.sa_flags = SA_SIGINFO;
@ -264,10 +411,11 @@ bool InstallHandler(void* owner, Callback callback)
#endif
}
m_handlers.push_back(RegisteredHandler{callback, owner, start_pc, code_size});
return true;
}
bool RemoveHandler(void* owner)
bool RemoveHandler(const void* owner)
{
std::lock_guard<std::mutex> guard(m_handler_lock);
auto it = std::find_if(m_handlers.begin(), m_handlers.end(),
@ -279,9 +427,11 @@ bool RemoveHandler(void* owner)
if (m_handlers.empty())
{
#if defined(_WIN32) && (defined(CPU_X64) || defined(CPU_AARCH64))
#if defined(_WIN32) && !defined(_UWP) && (defined(CPU_X64) || defined(CPU_AARCH64))
RemoveVectoredExceptionHandler(s_veh_handle);
s_veh_handle = nullptr;
#elif defined(_UWP)
// nothing to do here, any unregistered regions will be ignored
#elif defined(USE_SIGSEGV)
// restore old signal handler
#if defined(__APPLE__) || defined(__aarch64__)

View File

@ -8,10 +8,12 @@ enum class HandlerResult
ExecuteNextHandler,
};
using Callback = HandlerResult(*)(void* exception_pc, void* fault_address, bool is_write);
using Callback = HandlerResult (*)(void* exception_pc, void* fault_address, bool is_write);
using Handle = void*;
bool InstallHandler(void* owner, Callback callback);
bool RemoveHandler(void* owner);
u32 GetHandlerCodeSize();
bool InstallHandler(const void* owner, void* start_pc, u32 code_size, Callback callback);
bool RemoveHandler(const void* owner);
} // namespace Common::PageFaultHandler

View File

@ -93,6 +93,7 @@ void Timer::SleepUntil(Value value, bool exact)
if (diff <= 0)
return;
#ifndef _UWP
HANDLE timer = GetSleepTimer();
if (timer)
{
@ -110,6 +111,7 @@ void Timer::SleepUntil(Value value, bool exact)
return;
}
}
#endif
// falling back to sleep... bad.
Sleep(static_cast<DWORD>(static_cast<std::uint64_t>(diff) / 1000000));

View File

@ -2,7 +2,7 @@
#include "common/log.h"
Log_SetChannel(WindowInfo);
#if defined(_WIN32)
#if defined(_WIN32) && !defined(_UWP)
#include "common/windows_headers.h"
#include <dwmapi.h>

View File

@ -8,6 +8,7 @@ struct WindowInfo
{
Surfaceless,
Win32,
WinRT,
X11,
Wayland,
MacOS,

View File

@ -7,11 +7,13 @@
#define NOMINMAX 1
#endif
// require vista+
// require vista+, but don't set it when compiling for UWP
#ifndef WINAPI_FAMILY
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif
#include <windows.h>

View File

@ -25,7 +25,7 @@ static constexpr u32 RECOMPILE_COUNT_TO_FALL_BACK_TO_INTERPRETER = 20;
#ifdef WITH_RECOMPILER
// Currently remapping the code buffer doesn't work in macOS or Haiku.
#if !defined(__HAIKU__) && !defined(__APPLE__)
#if !defined(__HAIKU__) && !defined(__APPLE__) && !defined(_UWP)
#define USE_STATIC_CODE_BUFFER 1
#endif
@ -822,7 +822,10 @@ bool InitializeFastmem()
Assert(mode != CPUFastmemMode::MMap);
#endif
if (!Common::PageFaultHandler::InstallHandler(&s_host_code_map, handler))
s_code_buffer.ReserveCode(Common::PageFaultHandler::GetHandlerCodeSize());
if (!Common::PageFaultHandler::InstallHandler(&s_host_code_map, s_code_buffer.GetCodePointer(),
s_code_buffer.GetTotalSize(), handler))
{
Log_ErrorPrintf("Failed to install page fault handler");
return false;

View File

@ -369,10 +369,12 @@ struct Settings
static constexpr CPUFastmemMode DEFAULT_CPU_FASTMEM_MODE = CPUFastmemMode::Disabled;
#endif
#ifndef __ANDROID__
static constexpr AudioBackend DEFAULT_AUDIO_BACKEND = AudioBackend::Cubeb;
#else
#if defined(__ANDROID__)
static constexpr AudioBackend DEFAULT_AUDIO_BACKEND = AudioBackend::OpenSLES;
#elif defined(_UWP)
static constexpr AudioBackend DEFAULT_AUDIO_BACKEND = AudioBackend::XAudio2;
#else
static constexpr AudioBackend DEFAULT_AUDIO_BACKEND = AudioBackend::Cubeb;
#endif
static constexpr DisplayCropMode DEFAULT_DISPLAY_CROP_MODE = DisplayCropMode::Overscan;

6
src/duckstation-uwp/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
database/
inputprofiles/
resources/
shaders/
BundleArtifacts/
duckstation-uwp.pfx

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity
Name="57bcfd1f-31c1-4f8e-bf91-958732a81506"
Publisher="CN=Stenzek"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="57bcfd1f-31c1-4f8e-bf91-958732a81506" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>DuckStation</DisplayName>
<PublisherDisplayName>Stenzek</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="DuckStation.App">
<uap:VisualElements DisplayName="DuckStation" Description="A project for a C++/WinRT Universal Windows Platform (UWP) app directly implementing CoreApplication"
Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" BackgroundColor="transparent">
<uap:SplashScreen Image="Assets\SplashScreen.png" />
<uap:DefaultTile Square71x71Logo="Assets\SmallTile.png" Wide310x150Logo="Assets\WideTile.png" Square310x310Logo="Assets\LargeTile.png"/>
</uap:VisualElements>
<Extensions>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="duckstation-disc-images">
<uap:SupportedFileTypes>
<uap:FileType ContentType="application/x-cue">.cue</uap:FileType>
<uap:FileType ContentType="application/x-mame-chd">.chd</uap:FileType>
<uap:FileType ContentType="application/x-ecm">.ecm</uap:FileType>
<uap:FileType ContentType="application/x-iso9660-image">.iso</uap:FileType>
<uap:FileType ContentType="application/x-mds">.mds</uap:FileType>
<uap:FileType ContentType="application/x-psexe">.psexe</uap:FileType>
<uap:FileType ContentType="application/x-psf">.psf</uap:FileType>
<uap:FileType ContentType="application/x-psf">.minipsf</uap:FileType>
<uap:FileType ContentType="audio/x-mpegurl">.m3u</uap:FileType>
</uap:SupportedFileTypes>
<uap:DisplayName>DuckStation Disc Image</uap:DisplayName>
<uap:Logo>Assets\duck_128.png</uap:Logo>
</uap:FileTypeAssociation>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="codeGeneration"/>
<uap:Capability Name="removableStorage"/>
</Capabilities>
</Package>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/cppwinrt/tree/master/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>

View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\dep\msvc\vsprops\Configurations.props" />
<PropertyGroup Label="Globals">
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>false</CppWinRTRootNamespaceAutoMerge>
<MinimalCoreWin>true</MinimalCoreWin>
<ProjectGuid>{e2a6cea9-9537-4c61-b637-81f1f17ef638}</ProjectGuid>
<ProjectName>duckstation-uwp</ProjectName>
<RootNamespace>DuckStationUWP</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<CppWinRTGenerateWindowsMetadata>false</CppWinRTGenerateWindowsMetadata>
<CppWinRTOptimized>true</CppWinRTOptimized>
<CppWinRTRootNamespaceAutoMerge>false</CppWinRTRootNamespaceAutoMerge>
</PropertyGroup>
<PropertyGroup>
<IntDir>$(SolutionDir)build\$(Configuration)-$(Platform)\$(ProjectName)\</IntDir>
<OutDir>$(SolutionDir)build\$(Configuration)-$(Platform)\$(ProjectName)\</OutDir>
<GenerateProjectSpecificOutputFolder>false</GenerateProjectSpecificOutputFolder>
<TargetName>$(ProjectName)</TargetName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateKeyFile>duckstation-uwp.pfx</PackageCertificateKeyFile>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup>
<Import Project="..\..\dep\msvc\vsprops\Toolkit.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="PropertySheet.props" />
</ImportGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<DisableSpecificWarnings>
</DisableSpecificWarnings>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<Import Project="..\..\dep\msvc\vsprops\Base.props" />
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Image Include="Assets\duck_128.png" />
<Image Include="Assets\LargeTile.scale-100.png" />
<Image Include="Assets\LargeTile.scale-125.png" />
<Image Include="Assets\LargeTile.scale-150.png" />
<Image Include="Assets\LargeTile.scale-200.png" />
<Image Include="Assets\LargeTile.scale-400.png" />
<Image Include="Assets\LockScreenLogo.scale-200.png" />
<Image Include="Assets\SmallTile.scale-100.png" />
<Image Include="Assets\SmallTile.scale-125.png" />
<Image Include="Assets\SmallTile.scale-150.png" />
<Image Include="Assets\SmallTile.scale-200.png" />
<Image Include="Assets\SmallTile.scale-400.png" />
<Image Include="Assets\SplashScreen.scale-100.png" />
<Image Include="Assets\SplashScreen.scale-125.png" />
<Image Include="Assets\SplashScreen.scale-150.png" />
<Image Include="Assets\SplashScreen.scale-200.png" />
<Image Include="Assets\SplashScreen.scale-400.png" />
<Image Include="Assets\Square150x150Logo.scale-100.png" />
<Image Include="Assets\Square150x150Logo.scale-125.png" />
<Image Include="Assets\Square150x150Logo.scale-150.png" />
<Image Include="Assets\Square150x150Logo.scale-200.png" />
<Image Include="Assets\Square150x150Logo.scale-400.png" />
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-32.png" />
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-48.png" />
<Image Include="Assets\Square44x44Logo.scale-100.png" />
<Image Include="Assets\Square44x44Logo.scale-125.png" />
<Image Include="Assets\Square44x44Logo.scale-150.png" />
<Image Include="Assets\Square44x44Logo.scale-200.png" />
<Image Include="Assets\Square44x44Logo.scale-400.png" />
<Image Include="Assets\Square44x44Logo.targetsize-16.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24.png" />
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Image Include="Assets\Square44x44Logo.targetsize-256.png" />
<Image Include="Assets\Square44x44Logo.targetsize-32.png" />
<Image Include="Assets\Square44x44Logo.targetsize-48.png" />
<Image Include="Assets\StoreLogo.scale-100.png" />
<Image Include="Assets\StoreLogo.scale-125.png" />
<Image Include="Assets\StoreLogo.scale-150.png" />
<Image Include="Assets\StoreLogo.scale-200.png" />
<Image Include="Assets\StoreLogo.scale-400.png" />
<Image Include="Assets\Wide310x150Logo.scale-200.png" />
<Image Include="Assets\WideTile.scale-100.png" />
<Image Include="Assets\WideTile.scale-125.png" />
<Image Include="Assets\WideTile.scale-150.png" />
<Image Include="Assets\WideTile.scale-200.png" />
<Image Include="Assets\WideTile.scale-400.png" />
<Image Include="resources\address-book-new.png" />
<Image Include="resources\applications-system.png" />
<Image Include="resources\duck.png" />
<Image Include="resources\flag-eu.png" />
<Image Include="resources\flag-jp.png" />
<Image Include="resources\flag-uc.png" />
<Image Include="resources\media-cdrom.png" />
<Image Include="resources\multimedia-player.png" />
<Image Include="resources\star-0.png" />
<Image Include="resources\star-1.png" />
<Image Include="resources\star-2.png" />
<Image Include="resources\star-3.png" />
<Image Include="resources\star-4.png" />
<Image Include="resources\star-5.png" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="uwp_host_interface.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="database\gamedb.json">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="database\gamesettings.ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="duckstation-uwp.pfx" />
<None Include="inputprofiles\DualShock 4.ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="inputprofiles\Keyboard (No Numpad).ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="inputprofiles\Keyboard.ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="inputprofiles\PlayStation Classic Controller.ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="inputprofiles\Xbox Controller.ini">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="packages.config" />
<None Include="PropertySheet.props" />
<None Include="shaders\Cccalibrator.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\dolphinfx\bloom.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\dolphinfx\celshading.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\dolphinfx\scanlines.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\simple-brightness.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\simple-gamma.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="shaders\simple-sharpen.glsl">
<DeploymentContent>true</DeploymentContent>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="uwp_host_interface.h" />
<ClInclude Include="uwp_key_map.h" />
</ItemGroup>
<ItemGroup>
<Font Include="resources\fa-solid-900.ttf" />
</ItemGroup>
<ItemGroup>
<Text Include="database\chtdb.txt" />
<Text Include="database\gamecontrollerdb.txt" />
</ItemGroup>
<ItemGroup>
<Xml Include="database\compatibility.xml" />
</ItemGroup>
<ItemGroup>
<CommonDataFiles Include="$(SolutionDir)data\**\*.*">
<InProject>false</InProject>
</CommonDataFiles>
</ItemGroup>
<Target Name="CopyCommonDataFiles" BeforeTargets="PrepareForBuild" Inputs="@(CommonDataFiles)" Outputs="@(CommonDataFiles -> '$(ProjectDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying common data files" Importance="High" />
<Copy SourceFiles="@(CommonDataFiles)" DestinationFolder="$(ProjectDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Import Project="..\frontend-common\frontend-common.props" />
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>$(RootBuildDir)frontend-common\frontend-common.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="..\..\dep\msvc\vsprops\Targets.props" />
</Project>

View File

@ -0,0 +1,304 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="uwp_host_interface.cpp" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\Wide310x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LockScreenLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\duck_128.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SmallTile.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SmallTile.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SmallTile.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SmallTile.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SmallTile.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square150x150Logo.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\WideTile.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\WideTile.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\WideTile.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\WideTile.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\WideTile.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LargeTile.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LargeTile.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LargeTile.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LargeTile.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\LargeTile.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-16.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-24.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-32.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-48.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.targetsize-256.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-16.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-32.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-48.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-unplated_targetsize-256.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-16.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-24.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-32.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-48.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\Square44x44Logo.altform-lightunplated_targetsize-256.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\SplashScreen.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.scale-100.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.scale-125.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.scale-150.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.scale-200.png">
<Filter>Assets</Filter>
</Image>
<Image Include="Assets\StoreLogo.scale-400.png">
<Filter>Assets</Filter>
</Image>
<Image Include="resources\address-book-new.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\applications-system.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\duck.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\flag-eu.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\flag-jp.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\flag-uc.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\media-cdrom.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\multimedia-player.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-0.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-1.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-2.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-3.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-4.png">
<Filter>Data\resources</Filter>
</Image>
<Image Include="resources\star-5.png">
<Filter>Data\resources</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<Filter Include="Assets">
<UniqueIdentifier>{db9086fe-bacc-4437-8272-1aa6642082db}</UniqueIdentifier>
</Filter>
<Filter Include="Data">
<UniqueIdentifier>{fa7724ab-a364-49f2-9cdb-11307aa3f63e}</UniqueIdentifier>
</Filter>
<Filter Include="Data\resources">
<UniqueIdentifier>{8eda719e-58c6-484f-b00f-90ee69cd6cb5}</UniqueIdentifier>
</Filter>
<Filter Include="Data\shaders">
<UniqueIdentifier>{1d471d6d-942e-4e06-9b74-36c5620c9d43}</UniqueIdentifier>
</Filter>
<Filter Include="Data\inputprofiles">
<UniqueIdentifier>{bf7c6843-57df-4e82-bf4e-7ffea724e92d}</UniqueIdentifier>
</Filter>
<Filter Include="Data\database">
<UniqueIdentifier>{26b9c7e0-8acd-44be-848e-7da8e32238fa}</UniqueIdentifier>
</Filter>
<Filter Include="Data\shaders\dolphinfx">
<UniqueIdentifier>{1c1f164b-4184-422c-8d95-9c4cbb6a21eb}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="PropertySheet.props" />
<None Include="packages.config" />
<None Include="database\gamedb.json">
<Filter>Data\database</Filter>
</None>
<None Include="database\gamesettings.ini">
<Filter>Data\database</Filter>
</None>
<None Include="shaders\Cccalibrator.glsl">
<Filter>Data\shaders</Filter>
</None>
<None Include="shaders\simple-brightness.glsl">
<Filter>Data\shaders</Filter>
</None>
<None Include="shaders\simple-gamma.glsl">
<Filter>Data\shaders</Filter>
</None>
<None Include="shaders\simple-sharpen.glsl">
<Filter>Data\shaders</Filter>
</None>
<None Include="shaders\dolphinfx\bloom.glsl">
<Filter>Data\shaders\dolphinfx</Filter>
</None>
<None Include="shaders\dolphinfx\celshading.glsl">
<Filter>Data\shaders\dolphinfx</Filter>
</None>
<None Include="shaders\dolphinfx\scanlines.glsl">
<Filter>Data\shaders\dolphinfx</Filter>
</None>
<None Include="inputprofiles\Keyboard.ini">
<Filter>Data\inputprofiles</Filter>
</None>
<None Include="inputprofiles\PlayStation Classic Controller.ini">
<Filter>Data\inputprofiles</Filter>
</None>
<None Include="inputprofiles\Xbox Controller.ini">
<Filter>Data\inputprofiles</Filter>
</None>
<None Include="inputprofiles\DualShock 4.ini">
<Filter>Data\inputprofiles</Filter>
</None>
<None Include="inputprofiles\Keyboard (No Numpad).ini">
<Filter>Data\inputprofiles</Filter>
</None>
<None Include="duckstation-uwp.pfx" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="uwp_host_interface.h" />
<ClInclude Include="uwp_key_map.h" />
</ItemGroup>
<ItemGroup>
<Font Include="resources\fa-solid-900.ttf">
<Filter>Data\resources</Filter>
</Font>
</ItemGroup>
<ItemGroup>
<Text Include="database\gamecontrollerdb.txt">
<Filter>Data\database</Filter>
</Text>
<Text Include="database\chtdb.txt">
<Filter>Data\database</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<Xml Include="database\compatibility.xml">
<Filter>Data\database</Filter>
</Xml>
</ItemGroup>
</Project>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.210505.3" targetFramework="native" />
</packages>

View File

@ -0,0 +1,753 @@
#include "uwp_host_interface.h"
#include "common/assert.h"
#include "common/byte_stream.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/string_util.h"
#include "core/controller.h"
#include "core/gpu.h"
#include "core/host_display.h"
#include "core/system.h"
#include "frontend-common/controller_interface.h"
#include "frontend-common/d3d11_host_display.h"
#include "frontend-common/d3d12_host_display.h"
#include "frontend-common/fullscreen_ui.h"
#include "frontend-common/icon.h"
#include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "imgui_stdlib.h"
#include "uwp_key_map.h"
#include <cinttypes>
#include <cmath>
Log_SetChannel(UWPHostInterface);
#include <gamingdeviceinformation.h>
#include <winrt/Windows.Graphics.Display.Core.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.System.Profile.h>
static bool IsRunningOnXbox()
{
const auto version_info = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
const auto device_family = version_info.DeviceFamily();
return (device_family == L"Windows.Xbox");
}
UWPHostInterface::UWPHostInterface() = default;
UWPHostInterface::~UWPHostInterface() = default;
winrt::Windows::ApplicationModel::Core::IFrameworkView UWPHostInterface::CreateView()
{
return *this;
}
void UWPHostInterface::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& a)
{
winrt::Windows::ApplicationModel::Core::CoreApplication::Suspending({this, &UWPHostInterface::OnSuspending});
winrt::Windows::ApplicationModel::Core::CoreApplication::Resuming({this, &UWPHostInterface::OnResuming});
}
void UWPHostInterface::Load(const winrt::hstring&) {}
void UWPHostInterface::Uninitialize() {}
const char* UWPHostInterface::GetFrontendName() const
{
return "DuckStation UWP Frontend";
}
bool UWPHostInterface::Initialize()
{
Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEBUG);
if (!SetDirectories())
return false;
m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName());
m_flags.force_fullscreen_ui = true;
m_fullscreen_ui_enabled = true;
if (!CommonHostInterface::Initialize())
return false;
SetImGuiKeyMap();
const bool start_fullscreen = m_flags.start_fullscreen || g_settings.start_fullscreen;
if (!CreateDisplay(start_fullscreen))
{
Log_ErrorPrintf("Failed to create host display");
return false;
}
return true;
}
void UWPHostInterface::Shutdown()
{
DestroyDisplay();
CommonHostInterface::Shutdown();
}
void UWPHostInterface::SetDefaultSettings(SettingsInterface& si)
{
CommonHostInterface::SetDefaultSettings(si);
si.SetStringValue("CPU", "FastmemMode", "LUT");
si.SetStringValue("Main", "ControllerBackend", "XInput");
si.AddToStringList("GameList", "RecursivePaths", GetUserDirectoryRelativePath("games").c_str());
if (IsRunningOnXbox())
SetDefaultSettingsForXbox(si);
}
bool UWPHostInterface::CreateDisplay(bool fullscreen)
{
Assert(!m_display);
m_appview = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView();
m_appview.PreferredLaunchWindowingMode(
fullscreen ? winrt::Windows::UI::ViewManagement::ApplicationViewWindowingMode::FullScreen :
winrt::Windows::UI::ViewManagement::ApplicationViewWindowingMode::Auto);
m_window.Activate();
const auto di = winrt::Windows::Graphics::Display::DisplayInformation::GetForCurrentView();
const auto hdi = winrt::Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
const s32 resolution_scale = static_cast<s32>(di.ResolutionScale());
WindowInfo wi;
wi.type = WindowInfo::Type::WinRT;
wi.window_handle = winrt::get_unknown(m_window);
wi.surface_scale = static_cast<float>(resolution_scale) / 100.0f;
wi.surface_width = static_cast<u32>(m_window.Bounds().Width * wi.surface_scale);
wi.surface_height = static_cast<s32>(m_window.Bounds().Height * wi.surface_scale);
if (hdi)
{
try
{
const auto dm = hdi.GetCurrentDisplayMode();
const u32 hdmi_width = dm.ResolutionWidthInRawPixels();
const u32 hdmi_height = dm.ResolutionHeightInRawPixels();
wi.surface_refresh_rate = static_cast<float>(dm.RefreshRate());
Log_InfoPrintf("HDMI mode: %ux%u @ %.2f hz", hdmi_width, hdmi_height, wi.surface_refresh_rate);
// If we're running on Xbox, use the HDMI mode instead of the CoreWindow size.
// In UWP, the CoreWindow is always 1920x1080, even when running at 4K.
if (IsRunningOnXbox())
{
GAMING_DEVICE_MODEL_INFORMATION gdinfo = {};
if (SUCCEEDED(GetGamingDeviceModelInformation(&gdinfo)) && gdinfo.vendorId == GAMING_DEVICE_VENDOR_ID_MICROSOFT)
{
if (gdinfo.deviceId != GAMING_DEVICE_DEVICE_ID_XBOX_ONE)
{
Log_InfoPrintf("Overriding core window size %ux%u with HDMI size %ux%u", wi.surface_width,
wi.surface_height, hdmi_width, hdmi_height);
wi.surface_scale *= static_cast<float>(hdmi_width) / static_cast<float>(wi.surface_width);
wi.surface_width = hdmi_width;
wi.surface_height = hdmi_height;
}
}
}
}
catch (const winrt::hresult_error&)
{
}
}
if (g_settings.gpu_renderer == GPURenderer::HardwareD3D12)
m_display = std::make_unique<FrontendCommon::D3D12HostDisplay>();
else
m_display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
if (!m_display->CreateRenderDevice(wi, g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation) ||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation) ||
!CreateHostDisplayResources())
{
m_display->DestroyRenderDevice();
m_display.reset();
ReportError("Failed to create/initialize display render device");
return false;
}
if (!CreateHostDisplayResources())
Log_WarningPrint("Failed to create host display resources");
Log_InfoPrintf("Host display initialized at %ux%u resolution", m_display->GetWindowWidth(),
m_display->GetWindowHeight());
return true;
}
void UWPHostInterface::DestroyDisplay()
{
ReleaseHostDisplayResources();
if (m_display)
m_display->DestroyRenderDevice();
m_display.reset();
}
bool UWPHostInterface::AcquireHostDisplay()
{
return true;
}
void UWPHostInterface::ReleaseHostDisplay()
{
// restore vsync, since we don't want to burn cycles at the menu
m_display->SetVSync(true);
}
void UWPHostInterface::PollAndUpdate()
{
CommonHostInterface::PollAndUpdate();
ImGuiIO& io = ImGui::GetIO();
if (m_text_input_requested != io.WantTextInput)
{
const bool activate = io.WantTextInput;
Log_InfoPrintf("%s input pane...", activate ? "showing" : "hiding");
m_text_input_requested = activate;
m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [this, activate]() {
const auto input_pane = winrt::Windows::UI::ViewManagement::InputPane::GetForCurrentView();
if (input_pane)
{
if (activate)
input_pane.TryShow();
else
input_pane.TryHide();
}
});
}
}
void UWPHostInterface::RequestExit()
{
m_shutdown_flag.store(true);
m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal,
[this]() { winrt::Windows::ApplicationModel::Core::CoreApplication::Exit(); });
}
void UWPHostInterface::Run()
{
if (!Initialize())
{
Shutdown();
return;
}
m_emulation_thread = std::thread(&UWPHostInterface::EmulationThreadEntryPoint, this);
m_dispatcher.ProcessEvents(winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessUntilQuit);
m_shutdown_flag.store(true);
m_emulation_thread.join();
}
void UWPHostInterface::EmulationThreadEntryPoint()
{
if (m_fullscreen_ui_enabled)
{
FullscreenUI::SetDebugMenuAllowed(true);
FullscreenUI::QueueGameListRefresh();
}
// process events to pick up controllers before updating input map
PollAndUpdate();
UpdateInputMap();
if (m_was_running_on_suspend && ShouldSaveResumeState())
ResumeSystemFromMostRecentState();
while (!m_shutdown_flag.load())
{
RunCallbacks();
PollAndUpdate();
ImGui::NewFrame();
if (System::IsRunning())
{
if (m_display_all_frames)
System::RunFrame();
else
System::RunFrames();
UpdateControllerMetaState();
if (m_frame_step_request)
{
m_frame_step_request = false;
PauseSystem(true);
}
}
// rendering
{
DrawImGuiWindows();
ImGui::Render();
ImGui::EndFrame();
m_display->Render();
if (System::IsRunning())
{
System::UpdatePerformanceCounters();
if (m_throttler_enabled)
System::Throttle();
}
}
}
// Save state on exit so it can be resumed
if (!System::IsShutdown())
PowerOffSystem(ShouldSaveResumeState());
}
void UWPHostInterface::ReportMessage(const char* message)
{
Log_InfoPrint(message);
AddOSDMessage(message, 10.0f);
}
void UWPHostInterface::ReportError(const char* message)
{
Log_ErrorPrint(message);
if (!m_display)
return;
const bool was_in_frame = GImGui->FrameCount != GImGui->FrameCountEnded;
if (was_in_frame)
ImGui::EndFrame();
bool done = false;
while (!done)
{
RunCallbacks();
PollAndUpdate();
if (m_fullscreen_ui_enabled)
FullscreenUI::SetImGuiNavInputs();
ImGui::NewFrame();
done = FullscreenUI::DrawErrorWindow(message);
ImGui::EndFrame();
m_display->Render();
}
if (was_in_frame)
ImGui::NewFrame();
}
bool UWPHostInterface::ConfirmMessage(const char* message)
{
Log_InfoPrintf("Confirm: %s", message);
if (!m_display)
return true;
const bool was_in_frame = GImGui->FrameCount != GImGui->FrameCountEnded;
if (was_in_frame)
ImGui::EndFrame();
bool done = false;
bool result = true;
while (!done)
{
RunCallbacks();
PollAndUpdate();
if (m_fullscreen_ui_enabled)
FullscreenUI::SetImGuiNavInputs();
ImGui::NewFrame();
done = FullscreenUI::DrawConfirmWindow(message, &result);
ImGui::EndFrame();
m_display->Render();
}
if (was_in_frame)
ImGui::NewFrame();
return result;
}
void UWPHostInterface::RunLater(std::function<void()> callback)
{
std::unique_lock<std::mutex> lock(m_queued_callbacks_lock);
m_queued_callbacks.push_back(std::move(callback));
}
bool UWPHostInterface::IsFullscreen() const
{
return m_appview.IsFullScreenMode();
}
bool UWPHostInterface::SetFullscreen(bool enabled)
{
m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [this, enabled]() {
if (enabled)
m_appview.TryEnterFullScreenMode();
else
m_appview.ExitFullScreenMode();
});
return true;
}
void UWPHostInterface::RunCallbacks()
{
std::unique_lock<std::mutex> lock(m_queued_callbacks_lock);
while (!m_queued_callbacks.empty())
{
auto callback = std::move(m_queued_callbacks.front());
m_queued_callbacks.pop_front();
lock.unlock();
callback();
lock.lock();
}
}
void UWPHostInterface::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window)
{
m_window = window;
m_dispatcher = m_window.Dispatcher();
window.Closed({this, &UWPHostInterface::OnClosed});
window.SizeChanged({this, &UWPHostInterface::OnSizeChanged});
window.KeyDown({this, &UWPHostInterface::OnKeyDown});
window.KeyUp({this, &UWPHostInterface::OnKeyUp});
window.CharacterReceived({this, &UWPHostInterface::OnCharacterReceived});
window.PointerPressed({this, &UWPHostInterface::OnPointerPressed});
window.PointerReleased({this, &UWPHostInterface::OnPointerPressed});
window.PointerMoved({this, &UWPHostInterface::OnPointerMoved});
window.PointerWheelChanged({this, &UWPHostInterface::OnPointerWheelChanged});
}
bool UWPHostInterface::SetDirectories()
{
const auto install_location = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
m_program_directory = StringUtil::WideStringToUTF8String(install_location.Path());
if (m_program_directory.empty())
{
Log_ErrorPrintf("Failed to get install location");
return false;
}
Log_InfoPrintf("Program directory: %s", m_program_directory.c_str());
const auto local_location = winrt::Windows::Storage::ApplicationData::Current().LocalFolder();
m_user_directory = StringUtil::WideStringToUTF8String(local_location.Path());
if (m_user_directory.empty())
{
Log_ErrorPrintf("Failed to get user directory");
return false;
}
Log_InfoPrintf("User directory: %s", m_user_directory.c_str());
return true;
}
void UWPHostInterface::OnSuspending(const IInspectable&,
const winrt::Windows::ApplicationModel::SuspendingEventArgs& args)
{
if (IsEmulationThreadRunning())
{
RunLater([this]() {
if (ShouldSaveResumeState())
SaveResumeSaveState();
m_was_running_on_suspend.store(System::IsRunning());
PauseSystem(true);
m_suspend_sync_event.Signal();
});
m_suspend_sync_event.Wait();
}
}
void UWPHostInterface::OnResuming(const IInspectable&, const IInspectable&)
{
if (IsEmulationThreadRunning())
{
if (m_was_running_on_suspend.load())
RunLater([this]() { PauseSystem(false); });
}
else
{
RunLater([this]() {
if (ShouldSaveResumeState())
ResumeSystemFromMostRecentState();
});
}
}
void UWPHostInterface::OnClosed(const IInspectable&, const winrt::Windows::UI::Core::CoreWindowEventArgs& args)
{
if (IsEmulationThreadRunning())
{
m_shutdown_flag.store(true);
m_emulation_thread.join();
}
args.Handled(true);
}
void UWPHostInterface::OnSizeChanged(const IInspectable&,
const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args)
{
const auto size = args.Size();
const s32 width = static_cast<s32>(size.Width * m_display->GetWindowScale());
const s32 height = static_cast<s32>(size.Height * m_display->GetWindowScale());
if (IsEmulationThreadRunning())
{
RunLater([this, width, height]() {
m_display->ResizeRenderWindow(width, height);
OnHostDisplayResized();
});
}
args.Handled(true);
}
void UWPHostInterface::OnKeyDown(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args)
{
const auto status = args.KeyStatus();
if (!status.WasKeyDown && !status.IsKeyReleased && IsEmulationThreadRunning())
{
const HostKeyCode code = static_cast<HostKeyCode>(args.VirtualKey());
RunLater([this, code]() {
ImGuiIO& io = ImGui::GetIO();
if (code < countof(io.KeysDown))
io.KeysDown[code] = true;
if (!io.WantCaptureKeyboard)
HandleHostKeyEvent(code, 0, true);
});
}
args.Handled(true);
}
void UWPHostInterface::OnKeyUp(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args)
{
const auto status = args.KeyStatus();
if (status.WasKeyDown && status.IsKeyReleased && IsEmulationThreadRunning())
{
const HostKeyCode code = static_cast<HostKeyCode>(args.VirtualKey());
RunLater([this, code]() {
ImGuiIO& io = ImGui::GetIO();
if (code < countof(io.KeysDown))
io.KeysDown[code] = false;
if (!io.WantCaptureKeyboard)
HandleHostKeyEvent(code, 0, false);
});
}
args.Handled(true);
}
void UWPHostInterface::OnCharacterReceived(const IInspectable&,
const winrt::Windows::UI::Core::CharacterReceivedEventArgs& args)
{
if (IsEmulationThreadRunning())
{
const u32 code = args.KeyCode();
RunLater([this, code]() { ImGui::GetIO().AddInputCharacter(code); });
}
args.Handled(true);
}
void UWPHostInterface::OnPointerPressed(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
{
const auto pointer = args.CurrentPoint();
if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
UpdateMouseButtonState(pointer);
args.Handled(true);
}
void UWPHostInterface::OnPointerReleased(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
{
const auto pointer = args.CurrentPoint();
if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
UpdateMouseButtonState(pointer);
args.Handled(true);
}
void UWPHostInterface::OnPointerMoved(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
{
const auto pointer = args.CurrentPoint();
if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
{
const auto pos = pointer.Position();
const float x = pos.X * m_display->GetWindowScale();
const float y = pos.Y * m_display->GetWindowScale();
if (IsEmulationThreadRunning())
{
RunLater([this, x, y]() {
m_display->SetMousePosition(static_cast<s32>(x), static_cast<s32>(y));
if (ImGui::GetCurrentContext())
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos.x = x;
io.MousePos.y = y;
}
});
}
UpdateMouseButtonState(pointer);
}
args.Handled(true);
}
void UWPHostInterface::OnPointerWheelChanged(const IInspectable&,
const winrt::Windows::UI::Core::PointerEventArgs& args)
{
const auto pointer = args.CurrentPoint();
const auto properties = pointer.Properties();
const s32 delta = properties.MouseWheelDelta();
const bool horizontal = properties.IsHorizontalMouseWheel();
if (IsEmulationThreadRunning())
{
RunLater([this, delta, horizontal]() {
if (ImGui::GetCurrentContext())
{
ImGuiIO& io = ImGui::GetIO();
const float dw = static_cast<float>(std::clamp<s32>(delta, -1, 1));
if (horizontal)
io.MouseWheelH = dw;
else
io.MouseWheel = dw;
}
});
}
args.Handled(true);
}
void UWPHostInterface::UpdateMouseButtonState(const winrt::Windows::UI::Input::PointerPoint& point)
{
const auto properties = point.Properties();
const bool states[3] = {properties.IsLeftButtonPressed(), properties.IsRightButtonPressed(),
properties.IsMiddleButtonPressed()};
if (IsEmulationThreadRunning())
{
RunLater([this, states]() {
if (!ImGui::GetCurrentContext())
return;
ImGuiIO& io = ImGui::GetIO();
for (u32 i = 0; i < countof(states); i++)
{
if (io.MouseDown[i] == states[i])
continue;
io.MouseDown[i] = states[i];
HandleHostMouseEvent(static_cast<HostMouseButton>(i), states[i]);
}
});
}
}
std::optional<CommonHostInterface::HostKeyCode> UWPHostInterface::GetHostKeyCode(const std::string_view key_code) const
{
for (const auto& it : s_key_map)
{
if (key_code.compare(it.second) == 0)
return static_cast<HostKeyCode>(it.first);
}
return std::nullopt;
}
const char* UWPHostInterface::GetKeyCodeName(int key_code)
{
const auto it = s_key_map.find(key_code);
return (it != s_key_map.end()) ? it->second : nullptr;
}
void UWPHostInterface::SetImGuiKeyMap()
{
using namespace winrt::Windows::System;
ImGuiIO& io = ImGui::GetIO();
io.KeyMap[ImGuiKey_Tab] = static_cast<int>(VirtualKey::Tab);
io.KeyMap[ImGuiKey_LeftArrow] = static_cast<int>(VirtualKey::Left);
io.KeyMap[ImGuiKey_RightArrow] = static_cast<int>(VirtualKey::Right);
io.KeyMap[ImGuiKey_UpArrow] = static_cast<int>(VirtualKey::Up);
io.KeyMap[ImGuiKey_DownArrow] = static_cast<int>(VirtualKey::Down);
io.KeyMap[ImGuiKey_PageUp] = static_cast<int>(VirtualKey::PageUp);
io.KeyMap[ImGuiKey_PageDown] = static_cast<int>(VirtualKey::PageDown);
io.KeyMap[ImGuiKey_Home] = static_cast<int>(VirtualKey::Home);
io.KeyMap[ImGuiKey_End] = static_cast<int>(VirtualKey::End);
io.KeyMap[ImGuiKey_Insert] = static_cast<int>(VirtualKey::Insert);
io.KeyMap[ImGuiKey_Delete] = static_cast<int>(VirtualKey::Delete);
io.KeyMap[ImGuiKey_Backspace] = static_cast<int>(VirtualKey::Back);
io.KeyMap[ImGuiKey_Space] = static_cast<int>(VirtualKey::Space);
io.KeyMap[ImGuiKey_Enter] = static_cast<int>(VirtualKey::Enter);
io.KeyMap[ImGuiKey_Escape] = static_cast<int>(VirtualKey::Escape);
io.KeyMap[ImGuiKey_A] = static_cast<int>(VirtualKey::A);
io.KeyMap[ImGuiKey_C] = static_cast<int>(VirtualKey::C);
io.KeyMap[ImGuiKey_V] = static_cast<int>(VirtualKey::V);
io.KeyMap[ImGuiKey_X] = static_cast<int>(VirtualKey::X);
io.KeyMap[ImGuiKey_Y] = static_cast<int>(VirtualKey::Y);
io.KeyMap[ImGuiKey_Z] = static_cast<int>(VirtualKey::Z);
}
void UWPHostInterface::SetDefaultSettingsForXbox(SettingsInterface& si)
{
si.SetStringValue("GPU", "Renderer", "D3D12");
si.SetBoolValue("Main", "SyncToHostRefreshRate", true);
si.SetBoolValue("Display", "VSync", true);
si.SetBoolValue("Display", "DisplayAllFrames", true);
si.SetFloatValue("Display", "MaxFPS", 60.0f);
// Set up an analog controller in port 1.
si.SetStringValue("Controller1", "Type", "AnalogController");
si.SetStringValue("Controller1", "ButtonUp", "Controller0/Button11");
si.SetStringValue("Controller1", "ButtonDown", "Controller0/Button12");
si.SetStringValue("Controller1", "ButtonLeft", "Controller0/Button13");
si.SetStringValue("Controller1", "ButtonRight", "Controller0/Button14");
si.SetStringValue("Controller1", "ButtonStart", "Controller0/Button6");
si.SetStringValue("Controller1", "ButtonTriangle", "Controller0/Button3");
si.SetStringValue("Controller1", "ButtonCross", "Controller0/Button0");
si.SetStringValue("Controller1", "ButtonCircle", "Controller0/Button1");
si.SetStringValue("Controller1", "ButtonSquare", "Controller0/Button2");
si.SetStringValue("Controller1", "ButtonL1", "Controller0/Button9");
si.SetStringValue("Controller1", "ButtonL2", "Controller0/+Axis4");
si.SetStringValue("Controller1", "ButtonR1", "Controller0/Button10");
si.SetStringValue("Controller1", "ButtonR2", "Controller0/+Axis5");
si.SetStringValue("Controller1", "ButtonL3", "Controller0/Button7");
si.SetStringValue("Controller1", "ButtonR3", "Controller0/Button8");
si.SetStringValue("Controller1", "AxisLeftX", "Controller0/Axis0");
si.SetStringValue("Controller1", "AxisLeftY", "Controller0/Axis1");
si.SetStringValue("Controller1", "AxisRightX", "Controller0/Axis2");
si.SetStringValue("Controller1", "AxisRightY", "Controller0/Axis3");
si.SetStringValue("Controller1", "Rumble", "Controller0");
si.SetStringValue("Controller1", "ForceAnalogOnReset", "true");
si.SetStringValue("Controller1", "AnalogDPadInDigitalMode", "true");
// Repurpose the select button to open the menu.
// Not ideal, but all we can do until we have chords.
si.SetStringValue("Hotkeys", "OpenQuickMenu", "Controller0/Button4");
}
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
winrt::Windows::ApplicationModel::Core::CoreApplication::Run(winrt::make<UWPHostInterface>());
}

View File

@ -0,0 +1,117 @@
#pragma once
#include "common/event.h"
#include "common/window_info.h"
#include "common/windows_headers.h"
#include "core/host_display.h"
#include "core/host_interface.h"
#include "frontend-common/common_host_interface.h"
#include <Unknwn.h>
#include <array>
#include <deque>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <winrt/Windows.ApplicationModel.Core.h>
#include <winrt/Windows.Devices.Input.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.ViewManagement.Core.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include <winrt/base.h>
class INISettingsInterface;
class UWPHostInterface
: public CommonHostInterface,
public winrt::implements<UWPHostInterface, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource,
winrt::Windows::ApplicationModel::Core::IFrameworkView>
{
public:
UWPHostInterface();
~UWPHostInterface();
const char* GetFrontendName() const override;
bool Initialize() override;
void Shutdown() override;
void ReportMessage(const char* message) override;
void ReportError(const char* message) override;
bool ConfirmMessage(const char* message) override;
void RunLater(std::function<void()> callback) override;
bool IsFullscreen() const override;
bool SetFullscreen(bool enabled) override;
winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView();
void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView&);
void Load(const winrt::hstring&);
void Uninitialize();
void Run();
void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window);
protected:
enum : u32
{
DEFAULT_WINDOW_WIDTH = 1280,
DEFAULT_WINDOW_HEIGHT = 720
};
ALWAYS_INLINE bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
void SetDefaultSettings(SettingsInterface& si) override;
bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override;
void PollAndUpdate() override;
void RequestExit() override;
bool CreateDisplay(bool fullscreen);
void DestroyDisplay();
void RunCallbacks();
void EmulationThreadEntryPoint();
bool SetDirectories();
void OnSuspending(const IInspectable&, const winrt::Windows::ApplicationModel::SuspendingEventArgs& args);
void OnResuming(const IInspectable&, const IInspectable&);
void OnClosed(const IInspectable&, const winrt::Windows::UI::Core::CoreWindowEventArgs& args);
void OnSizeChanged(const IInspectable&, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args);
void OnKeyDown(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args);
void OnKeyUp(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args);
void OnCharacterReceived(const IInspectable&, const winrt::Windows::UI::Core::CharacterReceivedEventArgs& args);
void OnPointerPressed(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args);
void OnPointerReleased(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args);
void OnPointerMoved(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args);
void OnPointerWheelChanged(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args);
void UpdateMouseButtonState(const winrt::Windows::UI::Input::PointerPoint& point);
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
const char* GetKeyCodeName(int key_code);
void SetImGuiKeyMap();
void SetDefaultSettingsForXbox(SettingsInterface& si);
std::deque<std::function<void()>> m_queued_callbacks;
std::mutex m_queued_callbacks_lock;
winrt::Windows::UI::Core::CoreWindow m_window{nullptr};
winrt::Windows::UI::Core::CoreDispatcher m_dispatcher{nullptr};
winrt::Windows::UI::ViewManagement::ApplicationView m_appview{nullptr};
std::thread m_emulation_thread;
std::atomic_bool m_shutdown_flag{false};
bool m_text_input_requested = false;
Common::Event m_suspend_sync_event;
std::atomic_bool m_was_running_on_suspend{false};
std::atomic_bool m_was_running_on_background{false};
};

View File

@ -0,0 +1,149 @@
#include <map>
#include <winrt/Windows.System.h>
static const std::map<int, const char*> s_key_map = {
{static_cast<int>(winrt::Windows::System::VirtualKey::LeftButton), "LeftButton"},
{static_cast<int>(winrt::Windows::System::VirtualKey::RightButton), "RightButton"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Cancel), "Cancel"},
{static_cast<int>(winrt::Windows::System::VirtualKey::MiddleButton), "MiddleButton"},
{static_cast<int>(winrt::Windows::System::VirtualKey::XButton1), "XButton1"},
{static_cast<int>(winrt::Windows::System::VirtualKey::XButton2), "XButton2"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Back), "Back"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Tab), "Tab"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Clear), "Clear"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Enter), "Return"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Shift), "Shift"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Control), "Control"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Menu), "Menu"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Pause), "Pause"},
{static_cast<int>(winrt::Windows::System::VirtualKey::CapitalLock), "CapitalLock"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Kana), "Kana"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Hangul), "Hangul"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Junja), "Junja"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Final), "Final"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Hanja), "Hanja"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Kanji), "Kanji"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Escape), "Escape"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Convert), "Convert"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NonConvert), "NonConvert"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Accept), "Accept"},
{static_cast<int>(winrt::Windows::System::VirtualKey::ModeChange), "ModeChange"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Space), "Space"},
{static_cast<int>(winrt::Windows::System::VirtualKey::PageUp), "PageUp"},
{static_cast<int>(winrt::Windows::System::VirtualKey::PageDown), "PageDown"},
{static_cast<int>(winrt::Windows::System::VirtualKey::End), "End"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Home), "Home"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Left), "Left"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Up), "Up"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Right), "Right"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Down), "Down"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Select), "Select"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Print), "Print"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Execute), "Execute"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Snapshot), "Snapshot"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Insert), "Insert"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Delete), "Delete"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Help), "Help"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number0), "Number0"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number1), "Number1"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number2), "Number2"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number3), "Number3"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number4), "Number4"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number5), "Number5"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number6), "Number6"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number7), "Number7"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number8), "Number8"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Number9), "Number9"},
{static_cast<int>(winrt::Windows::System::VirtualKey::A), "A"},
{static_cast<int>(winrt::Windows::System::VirtualKey::B), "B"},
{static_cast<int>(winrt::Windows::System::VirtualKey::C), "C"},
{static_cast<int>(winrt::Windows::System::VirtualKey::D), "D"},
{static_cast<int>(winrt::Windows::System::VirtualKey::E), "E"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F), "F"},
{static_cast<int>(winrt::Windows::System::VirtualKey::G), "G"},
{static_cast<int>(winrt::Windows::System::VirtualKey::H), "H"},
{static_cast<int>(winrt::Windows::System::VirtualKey::I), "I"},
{static_cast<int>(winrt::Windows::System::VirtualKey::J), "J"},
{static_cast<int>(winrt::Windows::System::VirtualKey::K), "K"},
{static_cast<int>(winrt::Windows::System::VirtualKey::L), "L"},
{static_cast<int>(winrt::Windows::System::VirtualKey::M), "M"},
{static_cast<int>(winrt::Windows::System::VirtualKey::N), "N"},
{static_cast<int>(winrt::Windows::System::VirtualKey::O), "O"},
{static_cast<int>(winrt::Windows::System::VirtualKey::P), "P"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Q), "Q"},
{static_cast<int>(winrt::Windows::System::VirtualKey::R), "R"},
{static_cast<int>(winrt::Windows::System::VirtualKey::S), "S"},
{static_cast<int>(winrt::Windows::System::VirtualKey::T), "T"},
{static_cast<int>(winrt::Windows::System::VirtualKey::U), "U"},
{static_cast<int>(winrt::Windows::System::VirtualKey::V), "V"},
{static_cast<int>(winrt::Windows::System::VirtualKey::W), "W"},
{static_cast<int>(winrt::Windows::System::VirtualKey::X), "X"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Y), "Y"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Z), "Z"},
{static_cast<int>(winrt::Windows::System::VirtualKey::LeftWindows), "LeftWindows"},
{static_cast<int>(winrt::Windows::System::VirtualKey::RightWindows), "RightWindows"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Application), "Application"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Sleep), "Sleep"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad0), "Keypad+0"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad1), "Keypad+1"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad2), "Keypad+2"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad3), "Keypad+3"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad4), "Keypad+4"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad5), "Keypad+5"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad6), "Keypad+6"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad7), "Keypad+7"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad8), "Keypad+8"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberPad9), "Keypad+9"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Multiply), "Multiply"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Add), "Add"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Separator), "Separator"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Subtract), "Subtract"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Decimal), "Decimal"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Divide), "Divide"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F1), "F1"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F2), "F2"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F3), "F3"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F4), "F4"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F5), "F5"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F6), "F6"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F7), "F7"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F8), "F8"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F9), "F9"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F10), "F10"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F11), "F11"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F12), "F12"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F13), "F13"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F14), "F14"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F15), "F15"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F16), "F16"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F17), "F17"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F18), "F18"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F19), "F19"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F20), "F20"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F21), "F21"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F22), "F22"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F23), "F23"},
{static_cast<int>(winrt::Windows::System::VirtualKey::F24), "F24"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationView), "NavigationView"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationMenu), "NavigationMenu"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationUp), "NavigationUp"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationDown), "NavigationDown"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationLeft), "NavigationLeft"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationRight), "NavigationRight"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationAccept), "NavigationAccept"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NavigationCancel), "NavigationCancel"},
{static_cast<int>(winrt::Windows::System::VirtualKey::NumberKeyLock), "NumberKeyLock"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Scroll), "Scroll"},
{static_cast<int>(winrt::Windows::System::VirtualKey::LeftShift), "LeftShift"},
{static_cast<int>(winrt::Windows::System::VirtualKey::RightShift), "RightShift"},
{static_cast<int>(winrt::Windows::System::VirtualKey::LeftControl), "LeftControl"},
{static_cast<int>(winrt::Windows::System::VirtualKey::RightControl), "RightControl"},
{static_cast<int>(winrt::Windows::System::VirtualKey::LeftMenu), "LeftMenu"},
{static_cast<int>(winrt::Windows::System::VirtualKey::RightMenu), "RightMenu"},
{static_cast<int>(winrt::Windows::System::VirtualKey::GoBack), "GoBack"},
{static_cast<int>(winrt::Windows::System::VirtualKey::GoForward), "GoForward"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Refresh), "Refresh"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Stop), "Stop"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Search), "Search"},
{static_cast<int>(winrt::Windows::System::VirtualKey::Favorites), "Favorites"},
{static_cast<int>(winrt::Windows::System::VirtualKey::GoHome), "GoHome"}};

View File

@ -22,7 +22,6 @@
#include "core/system.h"
#include "core/texture_replacements.h"
#include "core/timers.h"
#include "cubeb_audio_stream.h"
#include "fullscreen_ui.h"
#include "game_list.h"
#include "icon.h"
@ -39,6 +38,10 @@
#include <cstring>
#include <ctime>
#ifndef _UWP
#include "cubeb_audio_stream.h"
#endif
#ifdef WITH_SDL2
#include "sdl_audio_stream.h"
#endif
@ -53,6 +56,7 @@
#ifdef _WIN32
#include "common/windows_headers.h"
#include "xaudio2_audio_stream.h"
#include <KnownFolders.h>
#include <ShlObj.h>
#include <mmsystem.h>
@ -173,6 +177,11 @@ void CommonHostInterface::InitializeUserDirectory()
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("shaders").c_str(), false);
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("textures").c_str(), false);
// Games directory for UWP because it's a pain to create them manually.
#ifdef _UWP
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("games").c_str(), false);
#endif
if (!result)
ReportError("Failed to create one or more user directories. This may cause issues at runtime.");
}
@ -636,8 +645,10 @@ std::unique_ptr<AudioStream> CommonHostInterface::CreateAudioStream(AudioBackend
case AudioBackend::Null:
return AudioStream::CreateNullAudioStream();
#ifndef _UWP
case AudioBackend::Cubeb:
return CubebAudioStream::Create();
#endif
#ifdef _WIN32
case AudioBackend::XAudio2:
@ -997,7 +1008,7 @@ void CommonHostInterface::SetUserDirectory()
}
else
{
#if defined(_WIN32)
#if defined(_WIN32) && !defined(_UWP)
// On Windows, use My Documents\DuckStation.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
@ -3221,7 +3232,7 @@ void CommonHostInterface::SetTimerResolutionIncreased(bool enabled)
m_timer_resolution_increased = enabled;
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
if (enabled)
timeBeginPeriod(1);
else

View File

@ -111,6 +111,8 @@ static constexpr std::array<const char*, static_cast<u32>(ControllerInterface::B
#endif
#ifdef _WIN32
TRANSLATABLE("ControllerInterface", "XInput"),
#endif
#ifdef WITH_DINPUT
TRANSLATABLE("ControllerInterface", "DInput"),
#endif
#ifdef ANDROID
@ -155,9 +157,11 @@ ControllerInterface::Backend ControllerInterface::GetDefaultBackend()
#include "sdl_controller_interface.h"
#endif
#ifdef _WIN32
#include "dinput_controller_interface.h"
#include "xinput_controller_interface.h"
#endif
#ifdef WITH_DINPUT
#include "dinput_controller_interface.h"
#endif
#ifdef WITH_EVDEV
#include "evdev_controller_interface.h"
#endif
@ -171,6 +175,8 @@ std::unique_ptr<ControllerInterface> ControllerInterface::Create(Backend type)
#ifdef _WIN32
if (type == Backend::XInput)
return std::make_unique<XInputControllerInterface>();
#endif
#ifdef WITH_DINPUT
if (type == Backend::DInput)
return std::make_unique<DInputControllerInterface>();
#endif

View File

@ -23,6 +23,8 @@ public:
#endif
#ifdef _WIN32
XInput,
#endif
#ifdef WITH_DINPUT
DInput,
#endif
#ifdef ANDROID

View File

@ -251,7 +251,11 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view
create_flags |= D3D11_CREATE_DEVICE_DEBUG;
ComPtr<IDXGIFactory> temp_dxgi_factory;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.GetAddressOf()));
#else
HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(temp_dxgi_factory.GetAddressOf()));
#endif
if (FAILED(hr))
{
Log_ErrorPrintf("Failed to create DXGI factory: 0x%08X", hr);
@ -385,6 +389,9 @@ bool D3D11HostDisplay::DoneRenderContextCurrent()
bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
{
HRESULT hr;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
if (m_window_info.type != WindowInfo::Type::Win32)
return false;
@ -423,7 +430,7 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
swap_chain_desc.BufferDesc.Height, m_using_flip_model_swap_chain ? "flip-discard" : "discard",
swap_chain_desc.Windowed ? "windowed" : "full-screen");
HRESULT hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
if (FAILED(hr) && m_using_flip_model_swap_chain)
{
Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard.");
@ -448,6 +455,42 @@ bool D3D11HostDisplay::CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode)
if (FAILED(hr))
Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed");
}
#else
if (m_window_info.type != WindowInfo::Type::WinRT)
return false;
ComPtr<IDXGIFactory2> factory2;
hr = m_dxgi_factory.As(&factory2);
if (FAILED(hr))
{
Log_ErrorPrintf("Failed to get DXGI factory: %08X", hr);
return false;
}
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.Width = m_window_info.surface_width;
swap_chain_desc.Height = m_window_info.surface_height;
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.BufferCount = 3;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain && !fullscreen_mode);
if (m_using_allow_tearing)
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
ComPtr<IDXGISwapChain1> swap_chain1;
hr = factory2->CreateSwapChainForCoreWindow(m_device.Get(), static_cast<IUnknown*>(m_window_info.window_handle),
&swap_chain_desc, nullptr, swap_chain1.GetAddressOf());
if (FAILED(hr))
{
Log_ErrorPrintf("CreateSwapChainForCoreWindow failed: 0x%08X", hr);
return false;
}
m_swap_chain = swap_chain1;
#endif
return CreateSwapChainRTV();
}
@ -476,18 +519,22 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
m_window_info.surface_width = backbuffer_desc.Width;
m_window_info.surface_height = backbuffer_desc.Height;
Log_InfoPrintf("Swap chain buffer size: %ux%u", m_window_info.surface_width, m_window_info.surface_height);
BOOL fullscreen = FALSE;
DXGI_SWAP_CHAIN_DESC desc;
if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen &&
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
if (m_window_info.type == WindowInfo::Type::Win32)
{
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
}
else
{
m_window_info.surface_refresh_rate = 0.0f;
BOOL fullscreen = FALSE;
DXGI_SWAP_CHAIN_DESC desc;
if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen &&
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
{
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
}
else
{
m_window_info.surface_refresh_rate = 0.0f;
}
}
return true;
@ -870,7 +917,11 @@ void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 he
HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList()
{
ComPtr<IDXGIFactory> dxgi_factory;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
#else
HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
#endif
if (FAILED(hr))
return {};

View File

@ -12,7 +12,7 @@
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(BuildingForUWP)'!='true'">
<ClCompile>
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DINPUT=1;WITH_DISCORD_PRESENCE=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\discord-rpc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -22,5 +22,5 @@
</Link>
</ItemDefinitionGroup>
<Import Project="..\..\dep\msvc\vsprops\SDL2Compile.props" />
</Project>
<Import Project="..\..\dep\msvc\vsprops\SDL2Compile.props" Condition="'$(BuildingForUWP)'!='true'" />
</Project>

View File

@ -4,9 +4,13 @@
<ItemGroup>
<ClCompile Include="common_host_interface.cpp" />
<ClCompile Include="controller_interface.cpp" />
<ClCompile Include="cubeb_audio_stream.cpp" />
<ClCompile Include="cubeb_audio_stream.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="d3d11_host_display.cpp" />
<ClCompile Include="dinput_controller_interface.cpp" />
<ClCompile Include="dinput_controller_interface.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="fullscreen_ui.cpp" />
<ClCompile Include="fullscreen_ui_progress_callback.cpp" />
<ClCompile Include="game_database.cpp" />
@ -14,7 +18,12 @@
<ClCompile Include="game_list.cpp" />
<ClCompile Include="game_settings.cpp" />
<ClCompile Include="http_downloader.cpp" />
<ClCompile Include="http_downloader_winhttp.cpp" />
<ClCompile Include="http_downloader_uwp.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'!='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="http_downloader_winhttp.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="icon.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_impl_dx11.cpp" />
@ -31,9 +40,15 @@
<ClCompile Include="postprocessing_shadergen.cpp" />
<ClCompile Include="cheevos.cpp" />
<ClCompile Include="save_state_selector_ui.cpp" />
<ClCompile Include="sdl_audio_stream.cpp" />
<ClCompile Include="sdl_controller_interface.cpp" />
<ClCompile Include="sdl_initializer.cpp" />
<ClCompile Include="sdl_audio_stream.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="sdl_controller_interface.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="sdl_initializer.cpp">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="vulkan_host_display.cpp" />
<ClCompile Include="xaudio2_audio_stream.cpp" />
<ClCompile Include="xinput_controller_interface.cpp" />
@ -41,9 +56,13 @@
<ItemGroup>
<ClInclude Include="common_host_interface.h" />
<ClInclude Include="controller_interface.h" />
<ClInclude Include="cubeb_audio_stream.h" />
<ClInclude Include="cubeb_audio_stream.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="d3d11_host_display.h" />
<ClInclude Include="dinput_controller_interface.h" />
<ClInclude Include="dinput_controller_interface.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="fullscreen_ui.h" />
<ClInclude Include="fullscreen_ui_progress_callback.h" />
<ClInclude Include="game_database.h" />
@ -51,7 +70,12 @@
<ClInclude Include="game_list.h" />
<ClInclude Include="game_settings.h" />
<ClInclude Include="http_downloader.h" />
<ClInclude Include="http_downloader_winhttp.h" />
<ClInclude Include="http_downloader_uwp.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'!='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="http_downloader_winhttp.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="icon.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_impl_dx11.h" />
@ -68,9 +92,15 @@
<ClInclude Include="postprocessing_shadergen.h" />
<ClInclude Include="cheevos.h" />
<ClInclude Include="save_state_selector_ui.h" />
<ClInclude Include="sdl_audio_stream.h" />
<ClInclude Include="sdl_controller_interface.h" />
<ClInclude Include="sdl_initializer.h" />
<ClInclude Include="sdl_audio_stream.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="sdl_controller_interface.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="sdl_initializer.h">
<ExcludedFromBuild Condition="'$(BuildingForUWP)'=='true'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="vulkan_host_display.h" />
<ClInclude Include="xaudio2_audio_stream.h" />
<ClInclude Include="xinput_controller_interface.h" />
@ -84,4 +114,4 @@
<Import Project="..\..\dep\msvc\vsprops\StaticLibrary.props" />
<Import Project="frontend-common.props" />
<Import Project="..\..\dep\msvc\vsprops\Targets.props" />
</Project>
</Project>

View File

@ -36,6 +36,7 @@
<ClCompile Include="xaudio2_audio_stream.cpp" />
<ClCompile Include="d3d12_host_display.cpp" />
<ClCompile Include="imgui_impl_dx12.cpp" />
<ClCompile Include="http_downloader_uwp.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="icon.h" />
@ -73,8 +74,9 @@
<ClInclude Include="xaudio2_audio_stream.h" />
<ClInclude Include="d3d12_host_display.h" />
<ClInclude Include="imgui_impl_dx12.h" />
<ClInclude Include="http_downloader_uwp.h" />
</ItemGroup>
<ItemGroup>
<None Include="font_roboto_regular.inl" />
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,166 @@
#include "http_downloader_uwp.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/string_util.h"
#include "common/timer.h"
#include <algorithm>
Log_SetChannel(HTTPDownloaderWinHttp);
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.Headers.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Web::Http;
namespace FrontendCommon {
HTTPDownloaderUWP::HTTPDownloaderUWP(std::string user_agent) : HTTPDownloader(), m_user_agent(std::move(user_agent)) {}
HTTPDownloaderUWP::~HTTPDownloaderUWP() = default;
std::unique_ptr<HTTPDownloader> HTTPDownloader::Create(const char* user_agent)
{
std::string user_agent_str;
if (user_agent)
user_agent_str = user_agent;
return std::make_unique<HTTPDownloaderUWP>(user_agent ? std::string(user_agent) : std::string());
}
HTTPDownloader::Request* HTTPDownloaderUWP::InternalCreateRequest()
{
Request* req = new Request();
return req;
}
void HTTPDownloaderUWP::InternalPollRequests()
{
// noop - uses async
}
bool HTTPDownloaderUWP::StartRequest(HTTPDownloader::Request* request)
{
Request* req = static_cast<Request*>(request);
try
{
const std::wstring url_wide(StringUtil::UTF8StringToWideString(req->url));
const Uri uri(url_wide);
if (!m_user_agent.empty() &&
!req->client.DefaultRequestHeaders().UserAgent().TryParseAdd(StringUtil::UTF8StringToWideString(m_user_agent)))
{
Log_WarningPrintf("Failed to set user agent to '%s'", m_user_agent.c_str());
}
if (req->type == Request::Type::Post)
{
const winrt::Windows::Storage::Streams::Buffer post_buf(static_cast<u32>(req->post_data.size()));
std::memcpy(post_buf.data(), req->post_data.data(), req->post_data.size());
const HttpBufferContent post_content(post_buf);
req->request_async = req->client.PostAsync(uri, post_content);
}
else
{
req->request_async = req->client.GetAsync(uri);
}
req->request_async.Completed(
[req](const IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress>& operation, AsyncStatus status) {
if (status == AsyncStatus::Completed)
{
Log_DevPrintf("Request for '%s' completed start portion", req->url.c_str());
try
{
req->state.store(Request::State::Receiving);
req->start_time = Common::Timer::GetValue();
const HttpResponseMessage response(req->request_async.get());
req->status_code = static_cast<s32>(response.StatusCode());
const IHttpContent content(response.Content());
req->receive_async = content.ReadAsBufferAsync();
req->receive_async.Completed(
[req](
const IAsyncOperationWithProgress<winrt::Windows::Storage::Streams::IBuffer, uint64_t>& inner_operation,
AsyncStatus inner_status) {
if (inner_status == AsyncStatus::Completed)
{
const winrt::Windows::Storage::Streams::IBuffer buffer(inner_operation.get());
if (buffer && buffer.Length() > 0)
{
req->data.resize(buffer.Length());
std::memcpy(req->data.data(), buffer.data(), req->data.size());
}
Log_DevPrintf("End of request '%s', %zu bytes received", req->url.c_str(), req->data.size());
req->state.store(Request::State::Complete);
}
else if (inner_status == AsyncStatus::Canceled)
{
// don't do anything, the request has been freed
}
else
{
Log_ErrorPrintf("Request for '%s' failed during recieve phase: %08X", req->url.c_str(),
inner_operation.ErrorCode().value);
req->status_code = -1;
req->state.store(Request::State::Complete);
}
});
}
catch (const winrt::hresult_error& err)
{
Log_ErrorPrintf("Failed to receive HTTP request for '%s': %08X %s", req->url.c_str(), err.code(),
StringUtil::WideStringToUTF8String(err.message()).c_str());
req->status_code = -1;
req->state.store(Request::State::Complete);
}
req->receive_async = nullptr;
}
else if (status == AsyncStatus::Canceled)
{
// don't do anything, the request has been freed
}
else
{
Log_ErrorPrintf("Request for '%s' failed during start phase: %08X", req->url.c_str(),
operation.ErrorCode().value);
req->status_code = -1;
req->state.store(Request::State::Complete);
}
req->request_async = nullptr;
});
}
catch (const winrt::hresult_error& err)
{
Log_ErrorPrintf("Failed to start HTTP request for '%s': %08X %s", req->url.c_str(), err.code(),
StringUtil::WideStringToUTF8String(err.message()).c_str());
req->callback(-1, req->data);
delete req;
return false;
}
Log_DevPrintf("Started HTTP request for '%s'", req->url.c_str());
req->state = Request::State::Started;
req->start_time = Common::Timer::GetValue();
return true;
}
void HTTPDownloaderUWP::CloseRequest(HTTPDownloader::Request* request)
{
Request* req = static_cast<Request*>(request);
if (req->request_async)
req->request_async.Cancel();
if (req->receive_async)
req->receive_async.Cancel();
req->client.Close();
delete req;
}
} // namespace FrontendCommon

View File

@ -0,0 +1,37 @@
#pragma once
#include "http_downloader.h"
#include "common/windows_headers.h"
#include <winrt/windows.Web.Http.h>
namespace FrontendCommon {
class HTTPDownloaderUWP final : public HTTPDownloader
{
public:
HTTPDownloaderUWP(std::string user_agent);
~HTTPDownloaderUWP() override;
protected:
Request* InternalCreateRequest() override;
void InternalPollRequests() override;
bool StartRequest(HTTPDownloader::Request* request) override;
void CloseRequest(HTTPDownloader::Request* request) override;
private:
struct Request : HTTPDownloader::Request
{
std::wstring object_name;
winrt::Windows::Web::Http::HttpClient client;
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Web::Http::HttpResponseMessage,
winrt::Windows::Web::Http::HttpProgress>
request_async{nullptr};
winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Windows::Storage::Streams::IBuffer, uint64_t>
receive_async{};
};
std::string m_user_agent;
};
} // namespace FrontendCommon

View File

@ -4,7 +4,7 @@
#include <cinttypes>
Log_SetChannel(FrontendCommon);
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
#include "common/windows_headers.h"
static bool SetScreensaverInhibitWin32(bool inhibit, const WindowInfo& wi)
@ -93,7 +93,7 @@ static bool SetScreensaverInhibit(bool inhibit, const WindowInfo& wi)
{
switch (wi.type)
{
#ifdef _WIN32
#if defined(_WIN32) && !defined(_UWP)
case WindowInfo::Type::Win32:
return SetScreensaverInhibitWin32(inhibit, wi);
#endif

View File

@ -23,6 +23,7 @@ ControllerInterface::Backend XInputControllerInterface::GetBackend() const
bool XInputControllerInterface::Initialize(CommonHostInterface* host_interface)
{
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
m_xinput_module = LoadLibraryW(L"xinput1_4");
if (!m_xinput_module)
{
@ -45,6 +46,10 @@ bool XInputControllerInterface::Initialize(CommonHostInterface* host_interface)
reinterpret_cast<decltype(m_xinput_get_state)>(GetProcAddress(m_xinput_module, "XInputGetState"));
m_xinput_set_state =
reinterpret_cast<decltype(m_xinput_set_state)>(GetProcAddress(m_xinput_module, "XInputSetState"));
#else
m_xinput_get_state = XInputGetState;
m_xinput_set_state = XInputSetState;
#endif
if (!m_xinput_get_state || !m_xinput_set_state)
{
Log_ErrorPrintf("Failed to get XInput function pointers.");