diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h index 8936ad1a02e7..425f7ed1b8b9 100644 --- a/Source/Core/Common/WindowSystemInfo.h +++ b/Source/Core/Common/WindowSystemInfo.h @@ -13,6 +13,7 @@ enum class WindowSystemType Wayland, FBDev, Haiku, + UWP, }; struct WindowSystemInfo @@ -43,4 +44,8 @@ struct WindowSystemInfo // Scale of the render surface. For hidpi systems, this will be >1. float render_surface_scale = 1.0f; + + // Renderer size for Core Windows + uint32_t render_width = 0; + uint32_t render_height = 0; }; diff --git a/Source/Core/Core/HW/GCPadEmu.cpp b/Source/Core/Core/HW/GCPadEmu.cpp index 470d2b8c2f8c..6e183483544c 100644 --- a/Source/Core/Core/HW/GCPadEmu.cpp +++ b/Source/Core/Core/HW/GCPadEmu.cpp @@ -171,11 +171,21 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface) EmulatedController::LoadDefaults(ciface); // Buttons - m_buttons->SetControlExpression(0, "`X`"); // A - m_buttons->SetControlExpression(1, "`Z`"); // B - m_buttons->SetControlExpression(2, "`C`"); // X - m_buttons->SetControlExpression(3, "`S`"); // Y - m_buttons->SetControlExpression(4, "`D`"); // Z +#if _UWP + // If we're running on UWP, we're likely on an Xbox. These defaults work for Xbox One & Series. + m_buttons->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Button A`"); // A + m_buttons->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Button B`"); // B + m_buttons->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Button X`"); // X + m_buttons->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Button Y`"); // Y + m_buttons->SetControlExpression(4, "`WGInput/0/Xbox One Game Controller:Bumper R`"); // Z + m_buttons->SetControlExpression(5, "`WGInput/0/Xbox One Game Controller:Menu`"); // Start +#else + m_buttons->SetControlExpression(0, "`Button A`"); // A + m_buttons->SetControlExpression(1, "`Button B`"); // B + m_buttons->SetControlExpression(2, "`Button X`"); // X + m_buttons->SetControlExpression(3, "`Button Y`"); // Y + m_buttons->SetControlExpression(4, "`Bumper R`"); // Z + #ifdef _WIN32 m_buttons->SetControlExpression(5, "`RETURN`"); // Start #else @@ -183,8 +193,22 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface) // Start m_buttons->SetControlExpression(5, "`Return`"); #endif +#endif +#if _UWP // D-Pad + m_dpad->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Pad N`"); // Up + m_dpad->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Pad S`"); // Down + m_dpad->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Pad W`"); // Left + m_dpad->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Pad E`"); // Right + + // C Stick + m_c_stick->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Right Y+`"); // Up + m_c_stick->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Right Y-`"); // Down + m_c_stick->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Right X-`"); // Left + m_c_stick->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Right X+`"); // Right +#else + // D-Pad m_dpad->SetControlExpression(0, "`T`"); // Up m_dpad->SetControlExpression(1, "`G`"); // Down m_dpad->SetControlExpression(2, "`F`"); // Left @@ -197,9 +221,15 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface) m_c_stick->SetControlExpression(3, "`L`"); // Right // Modifier m_c_stick->SetControlExpression(4, "`Ctrl`"); +#endif // Control Stick -#ifdef _WIN32 +#if _UWP + m_main_stick->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Left Y+`"); // Up + m_main_stick->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Left Y-`"); // Down + m_main_stick->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Left X-`"); // Left + m_main_stick->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Left X+`"); // Right +#elif _WIN32 m_main_stick->SetControlExpression(0, "`UP`"); // Up m_main_stick->SetControlExpression(1, "`DOWN`"); // Down m_main_stick->SetControlExpression(2, "`LEFT`"); // Left @@ -215,6 +245,7 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface) m_main_stick->SetControlExpression(2, "`Left`"); // Left m_main_stick->SetControlExpression(3, "`Right`"); // Right #endif + // Modifier m_main_stick->SetControlExpression(4, "`Shift`"); @@ -222,9 +253,17 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface) m_c_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0)); m_main_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0)); +#if _UWP // Triggers - m_triggers->SetControlExpression(0, "`Q`"); // L - m_triggers->SetControlExpression(1, "`W`"); // R + m_triggers->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Trigger L`"); // L + m_triggers->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Trigger R`"); // R + + // Rumble + m_rumble->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Rumble 0`"); +#else + m_triggers->SetControlExpression(0, "`Q`"); // L + m_triggers->SetControlExpression(1, "`W`"); // R +#endif } bool GCPad::GetMicButton() const diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp index dbad8fbead11..04af4a0b4101 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp @@ -198,17 +198,27 @@ void Nunchuk::DoState(PointerWrap& p) void Nunchuk::LoadDefaults(const ControllerInterface& ciface) { +#if _UWP // Stick - m_stick->SetControlExpression(0, "W"); // up - m_stick->SetControlExpression(1, "S"); // down - m_stick->SetControlExpression(2, "A"); // left - m_stick->SetControlExpression(3, "D"); // right + m_stick->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Left Y+`"); // up + m_stick->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Left Y-`"); // down + m_stick->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Left X-`"); // left + m_stick->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Left X+`"); // right +#else + m_stick->SetControlExpression(0, "W"); // up + m_stick->SetControlExpression(1, "S"); // down + m_stick->SetControlExpression(2, "A"); // left + m_stick->SetControlExpression(3, "D"); // right +#endif // Because our defaults use keyboard input, set calibration shape to a square. m_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0)); // Buttons -#ifdef _WIN32 +#if _UWP + m_buttons->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Trigger L`"); // C + m_buttons->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Trigger R`"); // Z +#elif _WIN32 m_buttons->SetControlExpression(0, "LCONTROL"); // C m_buttons->SetControlExpression(1, "LSHIFT"); // Z #elif __APPLE__ diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 5bc19f48e89a..14b268a3273f 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -666,18 +666,32 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface) m_buttons->SetControlExpression(0, "`Left Click`"); // B m_buttons->SetControlExpression(1, "`Right Click`"); +#elif _UWP + // If we're running on UWP, we're likely on an Xbox. These defaults work for Xbox One & Series. + m_buttons->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Button A`"); // A + m_buttons->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Button B`"); // B #else // A m_buttons->SetControlExpression(0, "`Click 0`"); // B m_buttons->SetControlExpression(1, "`Click 1`"); #endif + +#if _UWP + m_buttons->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Button X`"); + m_buttons->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Button Y`"); + m_buttons->SetControlExpression(4, "WGInput/0/Xbox One Game Controller:View"); + m_buttons->SetControlExpression(5, "WGInput/0/Xbox One Game Controller:Menu"); +#else m_buttons->SetControlExpression(2, "`1`"); // 1 m_buttons->SetControlExpression(3, "`2`"); // 2 m_buttons->SetControlExpression(4, "Q"); // - m_buttons->SetControlExpression(5, "E"); // + +#endif -#ifdef _WIN32 +#if _UWP + m_buttons->SetControlExpression(6, "WGInput/0/Xbox One Game Controller:Menu & View"); // Home +#elif _WIN32 m_buttons->SetControlExpression(6, "RETURN"); // Home #else // Home @@ -692,14 +706,26 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface) m_shake->SetControlExpression(i, "`Click 2`"); #endif +#if _UWP // Pointing (IR) + m_ir->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Right Y+`"); + m_ir->SetControlExpression(1, "`WGInput/0/Xbox One Game Controller:Right Y-`"); + m_ir->SetControlExpression(2, "`WGInput/0/Xbox One Game Controller:Right X-`"); + m_ir->SetControlExpression(3, "`WGInput/0/Xbox One Game Controller:Right X+`"); +#else m_ir->SetControlExpression(0, "`Cursor Y-`"); m_ir->SetControlExpression(1, "`Cursor Y+`"); m_ir->SetControlExpression(2, "`Cursor X-`"); m_ir->SetControlExpression(3, "`Cursor X+`"); +#endif // DPad -#ifdef _WIN32 +#if _UWP + m_dpad->SetControlExpression(0, "WGInput/0/Xbox One Game Controller:Pad N"); // Up + m_dpad->SetControlExpression(1, "WGInput/0/Xbox One Game Controller:Pad S"); // Down + m_dpad->SetControlExpression(2, "WGInput/0/Xbox One Game Controller:Pad W"); // Left + m_dpad->SetControlExpression(3, "WGInput/0/Xbox One Game Controller:Pad E"); // Right +#elif _WIN32 m_dpad->SetControlExpression(0, "UP"); // Up m_dpad->SetControlExpression(1, "DOWN"); // Down m_dpad->SetControlExpression(2, "LEFT"); // Left @@ -730,6 +756,10 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface) m_imu_gyroscope->SetControlExpression(4, "`Gyro Yaw Left`"); m_imu_gyroscope->SetControlExpression(5, "`Gyro Yaw Right`"); +#if _UWP + m_rumble->SetControlExpression(0, "`WGInput/0/Xbox One Game Controller:Rumble 0`"); +#endif + // Enable Nunchuk: constexpr ExtensionNumber DEFAULT_EXT = ExtensionNumber::NUNCHUK; m_attachments->SetSelectedAttachment(DEFAULT_EXT); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp index d57f913be3b1..aa6a9a53075c 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#if defined(__LIBUSB__) #include "Core/IOS/USB/Bluetooth/BTReal.h" #include @@ -732,3 +733,4 @@ void BluetoothRealDevice::HandleBulkOrIntrTransfer(libusb_transfer* tr) m_current_transfers.erase(tr); } } // namespace IOS::HLE +#endif diff --git a/Source/Core/Core/IOS/USB/LibusbDevice.cpp b/Source/Core/Core/IOS/USB/LibusbDevice.cpp index e909169bf1d6..6469b82e141f 100644 --- a/Source/Core/Core/IOS/USB/LibusbDevice.cpp +++ b/Source/Core/Core/IOS/USB/LibusbDevice.cpp @@ -1,6 +1,7 @@ // Copyright 2017 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#if defined(__LIBUSB__) #include "Core/IOS/USB/LibusbDevice.h" #include @@ -474,3 +475,4 @@ int LibusbDevice::ReleaseAllInterfacesForCurrentConfig() const return ReleaseAllInterfaces(config_num); } } // namespace IOS::HLE::USB +#endif diff --git a/Source/Core/DolphinUWP/App.cpp b/Source/Core/DolphinUWP/App.cpp new file mode 100644 index 000000000000..165fb47f1435 --- /dev/null +++ b/Source/Core/DolphinUWP/App.cpp @@ -0,0 +1,332 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define SDL_MAIN_HANDLED + +using namespace winrt; + +using namespace Windows; +using namespace Windows::Storage; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation::Numerics; +using namespace Windows::UI::Composition; +using namespace winrt::Windows::Storage; +using namespace winrt::Windows::Storage::Pickers; +using namespace Windows::Graphics::Display::Core; + +using winrt::Windows::UI::Core::BackRequestedEventArgs; +using winrt::Windows::UI::Core::CoreProcessEventsOption; +using winrt::Windows::UI::Core::CoreWindow; + +Common::Flag m_running{true}; +Common::Flag m_shutdown_requested{false}; +Common::Flag m_tried_graceful_shutdown{false}; +winrt::hstring m_launchOnExit; + +struct App : implements +{ + IFrameworkView CreateView() { return *this; } + + void Initialize(CoreApplicationView const& v) + { + v.Activated({this, &App::OnActivate}); + CoreApplication::EnteredBackground({this, &App::EnteredBackground}); + CoreApplication::Suspending({this, &App::Suspending}); + } + + void Load(hstring const&) {} + + void Uninitialize() {} + + void Run() + { + while (m_running.IsSet()) + { + if (m_shutdown_requested.TestAndClear()) + { + const auto ios = IOS::HLE::GetIOS(); + const auto stm = ios ? ios->GetDeviceByName("/dev/stm/eventhook") : nullptr; + if (!m_tried_graceful_shutdown.IsSet() && stm && + std::static_pointer_cast(stm)->HasHookInstalled()) + { + ProcessorInterface::PowerButton_Tap(); + m_tried_graceful_shutdown.Set(); + } + else + { + m_running.Clear(); + } + } + + ::Core::HostDispatchJobs(); + CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents( + CoreProcessEventsOption::ProcessAllIfPresent); + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + winrt::fire_and_forget InitializeDolphinFromFile(std::string path) + { + if (path.empty()) + { + FileOpenPicker openPicker; + openPicker.ViewMode(PickerViewMode::List); + openPicker.SuggestedStartLocation(PickerLocationId::ComputerFolder); + openPicker.FileTypeFilter().Append(L".iso"); + openPicker.FileTypeFilter().Append(L".ciso"); + openPicker.FileTypeFilter().Append(L".rvz"); + openPicker.FileTypeFilter().Append(L".wbfs"); + openPicker.FileTypeFilter().Append(L".gcm"); + openPicker.FileTypeFilter().Append(L".gcz"); + openPicker.FileTypeFilter().Append(L".json"); + + auto file = co_await openPicker.PickSingleFileAsync(); + if (file) + { + path = winrt::to_string(file.Path().data()); + } + } + + CoreWindow window = CoreWindow::GetForCurrentThread(); + void* abi = winrt::get_abi(window); + + WindowSystemInfo wsi; + wsi.type = WindowSystemType::UWP; + wsi.render_window = abi; + wsi.render_surface = abi; + wsi.render_width = window.Bounds().Width; + wsi.render_height = window.Bounds().Height; + + auto navigation = winrt::Windows::UI::Core::SystemNavigationManager::GetForCurrentView(); + + // UWP on Xbox One triggers a back request whenever the B button is pressed + // which can result in the app being suspended if unhandled + navigation.BackRequested([](const winrt::Windows::Foundation::IInspectable&, + const BackRequestedEventArgs& args) { args.Handled(true); }); + + GAMING_DEVICE_MODEL_INFORMATION info = {}; + GetGamingDeviceModelInformation(&info); + if (info.vendorId == GAMING_DEVICE_VENDOR_ID_MICROSOFT) + { + HdmiDisplayInformation hdi = HdmiDisplayInformation::GetForCurrentView(); + if (hdi) + { + wsi.render_width = hdi.GetCurrentDisplayMode().ResolutionWidthInRawPixels(); + wsi.render_height = hdi.GetCurrentDisplayMode().ResolutionHeightInRawPixels(); + } + } + + std::unique_ptr boot = + BootParameters::GenerateFromFile(path, BootSessionData("", DeleteSavestateAfterBoot::No)); + + UICommon::SetUserDirectory(winrt::to_string(ApplicationData::Current().LocalFolder().Path())); + UICommon::CreateDirectories(); + UICommon::Init(); + UICommon::InitControllers(wsi); + + if (!BootManager::BootCore(std::move(boot), wsi)) + { + fprintf(stderr, "Could not boot the specified file\n"); + } + } + + void SetWindow(CoreWindow const& w) { w.Closed({this, &App::OnClosed}); } + + void OnClosed(const IInspectable&, const winrt::Windows::UI::Core::CoreWindowEventArgs& args) + { + m_shutdown_requested.Set(); + } + + void OnActivate(const winrt::Windows::ApplicationModel::Core::CoreApplicationView&, + const winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs& args) + { + std::stringstream filePath; + + if (args.Kind() == Windows::ApplicationModel::Activation::ActivationKind::Protocol) + { + auto protocolActivatedEventArgs{ + args.as()}; + auto query = protocolActivatedEventArgs.Uri().QueryParsed(); + + for (uint32_t i = 0; i < query.Size(); i++) + { + auto arg = query.GetAt(i); + + // parse command line string + if (arg.Name() == winrt::hstring(L"cmd")) + { + std::string argVal = winrt::to_string(arg.Value()); + + // Strip the executable from the cmd argument + if (argVal.starts_with("dolphin.exe")) + { + argVal = argVal.substr(11, argVal.length()); + } + + std::istringstream iss(argVal); + std::string s; + + // Maintain slashes while reading the quotes + while (iss >> std::quoted(s, '"', (char)0)) + { + filePath << s; + } + } + else if (arg.Name() == winrt::hstring(L"launchOnExit")) + { + // For if we want to return to a frontend + m_launchOnExit = arg.Value(); + } + } + } + + // Defaults to file picker if no path is present. + InitializeDolphinFromFile(filePath.str()); + + CoreWindow window = CoreWindow::GetForCurrentThread(); + window.Activate(); + } + + void EnteredBackground(const IInspectable&, + const winrt::Windows::ApplicationModel::EnteredBackgroundEventArgs& args) + { + } + + void Suspending(const IInspectable&, + const winrt::Windows::ApplicationModel::SuspendingEventArgs& args) + { + m_shutdown_requested.Set(); + + // The Series S/X quits fast, so let's immediately shutdown to ensure all the caches save. + Core::Stop(); + Core::Shutdown(); + UICommon::Shutdown(); + + if (!m_launchOnExit.empty()) + { + winrt::Windows::Foundation::Uri m_uri{m_launchOnExit}; + auto asyncOperation = winrt::Windows::System::Launcher::LaunchUriAsync(m_uri); + asyncOperation.Completed([](winrt::Windows::Foundation::IAsyncOperation const& sender, + winrt::Windows::Foundation::AsyncStatus const asyncStatus) { + CoreApplication::Exit(); + }); + } + } +}; + +int WINAPIV WinMain() +{ + winrt::init_apartment(); + + CoreApplication::Run(make()); + + winrt::uninit_apartment(); + + return 0; +} + +std::vector Host_GetPreferredLocales() +{ + return {}; +} + +void Host_NotifyMapLoaded() +{ +} + +void Host_RefreshDSPDebuggerWindow() +{ +} + +bool Host_UIBlocksControllerState() +{ + return false; +} + +void Host_Message(HostMessageID id) +{ +} + +void Host_UpdateTitle(const std::string& title) +{ +} + +void Host_UpdateDisasmDialog() +{ +} + +void Host_UpdateMainFrame() +{ +} + +void Host_RequestRenderWindowSize(int width, int height) +{ +} + +bool Host_RendererHasFocus() +{ + return true; +} + +bool Host_RendererHasFullFocus() +{ + // Mouse capturing isn't implemented + return Host_RendererHasFocus(); +} + +bool Host_RendererIsFullscreen() +{ + return true; +} + +void Host_YieldToUI() +{ +} + +void Host_TitleChanged() +{ +} + +void Host_UpdateDiscordClientID(const std::string& client_id) +{ +} + +bool Host_UpdateDiscordPresenceRaw(const std::string& details, const std::string& state, + const std::string& large_image_key, + const std::string& large_image_text, + const std::string& small_image_key, + const std::string& small_image_text, + const int64_t start_timestamp, const int64_t end_timestamp, + const int party_size, const int party_max) +{ + return false; +} + +std::unique_ptr Host_CreateGBAHost(std::weak_ptr core) +{ + return nullptr; +} diff --git a/Source/Core/DolphinUWP/App.h b/Source/Core/DolphinUWP/App.h new file mode 100644 index 000000000000..a780352d89f7 --- /dev/null +++ b/Source/Core/DolphinUWP/App.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class App + : public winrt::implements +{ +public: + 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); + void UpdateRunningFlag(); + void OnActivated(CoreApplicationView const& /*applicationView*/, + winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& /*args*/); + +private: + Common::Flag m_running{true}; + Common::Flag m_shutdown_requested{false}; + Common::Flag m_tried_graceful_shutdown{false}; + winrt::Windows::UI::Core::CoreDispatcher m_dispatcher{nullptr}; +}; diff --git a/Source/Core/DolphinUWP/Assets/LockScreenLogo.scale-200.png b/Source/Core/DolphinUWP/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 000000000000..eef3e094d41d Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/LockScreenLogo.scale-200.png differ diff --git a/Source/Core/DolphinUWP/Assets/SplashScreen.scale-200.png b/Source/Core/DolphinUWP/Assets/SplashScreen.scale-200.png new file mode 100644 index 000000000000..2646ffa91756 Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/SplashScreen.scale-200.png differ diff --git a/Source/Core/DolphinUWP/Assets/Square150x150Logo.scale-200.png b/Source/Core/DolphinUWP/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 000000000000..98c94ce550c6 Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/Square150x150Logo.scale-200.png differ diff --git a/Source/Core/DolphinUWP/Assets/Square44x44Logo.scale-200.png b/Source/Core/DolphinUWP/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 000000000000..be542f706459 Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/Square44x44Logo.scale-200.png differ diff --git a/Source/Core/DolphinUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Source/Core/DolphinUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 000000000000..6c9c746475ab Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/Source/Core/DolphinUWP/Assets/StoreLogo.png b/Source/Core/DolphinUWP/Assets/StoreLogo.png new file mode 100644 index 000000000000..9c01f551c173 Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/StoreLogo.png differ diff --git a/Source/Core/DolphinUWP/Assets/Wide310x150Logo.scale-200.png b/Source/Core/DolphinUWP/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 000000000000..d72053b3b8c0 Binary files /dev/null and b/Source/Core/DolphinUWP/Assets/Wide310x150Logo.scale-200.png differ diff --git a/Source/Core/DolphinUWP/DolphinUWP.vcxproj b/Source/Core/DolphinUWP/DolphinUWP.vcxproj new file mode 100644 index 000000000000..ca46056012eb --- /dev/null +++ b/Source/Core/DolphinUWP/DolphinUWP.vcxproj @@ -0,0 +1,138 @@ + + + + + true + true + true + {de8732bc-4ca5-4d39-b5d3-03d318ba9c02} + DolphinUWP + DolphinUWP + en-US + 15.0 + true + Windows Store + 10.0 + 10.0.22000.0 + 10.0.17134.0 + true + + + + + + + + + + Application + v143 + v142 + v141 + v140 + Unicode + + + true + true + + + false + true + false + + + + + + + + + False + True + C9F9E628DB2F5338D9F5D62D65BBD452442B5079 + SHA256 + False + True + Always + x64 + 0 + + + Dolphin$(TargetSuffix) + + + Dolphin$(TargetSuffix) + + + + NotUsing + pch.h + $(IntDir)pch.pch + Level2 + %(AdditionalOptions) /bigobj + WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + + + false + + + + + _DEBUG;_UWP;%(PreprocessorDefinitions) + NDEBUG;_UWP;%(PreprocessorDefinitions) + NDEBUG;_UWP;%(PreprocessorDefinitions) + stdcpp20 + $(ExternalsDir)fmt\include;$(ExternalsDir)SDL;%(AdditionalIncludeDirectories) + + + true + true + + DolphinLib/bin/DolphinLib.lib;Bochs_disasm/bin/Bochs_disasm.lib;bzip2/bin/bzip2.lib;cubeb/bin/cubeb.lib;curl/bin/curl.lib;discord-rpc/bin/discord-rpc.lib;ed25519/bin/ed25519.lib;enet/bin/enet.lib;FatFs/bin/FatFs.lib;fmt/bin/fmt.lib;FreeSurround/bin/FreeSurround.lib;glslang/bin/glslang.lib;imgui/bin/imgui.lib;liblzma/bin/liblzma.lib;libusb-1.0/bin/libusb-1.0.lib;LZO/bin/LZO.lib;mbedtls/bin/mbedtls.lib;mGBA/bin/mGBA.lib;miniupnpc/bin/miniupnpc.lib;minizip/bin/minizip.lib;picojson/bin/picojson.lib;pugixml/bin/pugixml.lib;SoundTouch/bin/SoundTouch.lib;spirv_cross/bin/spirv_cross.lib;xxhash/bin/xxhash.lib;zlib-ng/bin/zlib-ng.lib;zstd/bin/zstd.lib;spng/bin/spng.lib;SFML_Network/bin/SFML_Network.lib;%(AdditionalDependencies) + $(BuildRootDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + comsuppw.lib;comsuppwd.lib + + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + {89e9b32e-a86a-47c3-a948-d2b1622925ce} + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Source/Core/DolphinUWP/Package.appxmanifest b/Source/Core/DolphinUWP/Package.appxmanifest new file mode 100644 index 000000000000..1008d63f08e6 --- /dev/null +++ b/Source/Core/DolphinUWP/Package.appxmanifest @@ -0,0 +1,70 @@ + + + + + + Dolphin Emulator + Dolphin Emulator + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + .iso + .ciso + .wbfs + .rvz + .gcz + .gcm + .json + + + + + + + .iso + .ciso + .rvz + .wbfs + .gcm + .gcz + .json + + Dolphin Emulator + + + + + Dolphin Emulator + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Core/DolphinUWP/pch.h b/Source/Core/DolphinUWP/pch.h new file mode 100644 index 000000000000..1a5ff3e7a254 --- /dev/null +++ b/Source/Core/DolphinUWP/pch.h @@ -0,0 +1,8 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp index 327002c3a301..1f7f95b3abe1 100644 --- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp @@ -199,7 +199,11 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) { Common::ScopeGuard init_guard([this] { m_init_event.Set(); }); +#if _UWP + if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0) +#else if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) != 0) +#endif { ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize"); return; @@ -227,7 +231,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) } } -#ifdef _WIN32 +#if defined(_WIN32) && !_UWP // This is a hack to workaround SDL_hidapi using window messages to detect device // removal/arrival, yet no part of SDL pumps messages for it. It can hopefully be removed in the // future when SDL fixes the issue. Note this is a separate issue from SDL_HINT_JOYSTICK_THREAD. @@ -244,7 +248,7 @@ InputBackend::InputBackend(ControllerInterface* controller_interface) if (!HandleEventAndContinue(e)) return; -#ifdef _WIN32 +#if defined(_WIN32) && !_UWP MSG msg; while (window_handle && PeekMessage(&msg, window_handle, 0, 0, PM_NOREMOVE)) { diff --git a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp index 21e984796468..cb106cbe7fe9 100644 --- a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp @@ -14,7 +14,11 @@ #include "Common/Flag.h" #include "Common/Logging/Log.h" + +#if !_UWP #include "InputCommon/ControllerInterface/DInput/DInput.h" +#endif + #include "InputCommon/ControllerInterface/WGInput/WGInput.h" #include "InputCommon/ControllerInterface/XInput/XInput.h" @@ -44,7 +48,9 @@ _Pre_satisfies_(EventDataSize >= sizeof(CM_NOTIFY_EVENT_DATA)) static DWORD CALL // TODO: we could easily use the message passed alongside this event, which tells // whether a device was added or removed, to avoid removing old, still connected, devices g_controller_interface.PlatformPopulateDevices([] { +#if !_UWP ciface::DInput::PopulateDevices(s_hwnd); +#endif ciface::XInput::PopulateDevices(); }); } @@ -75,7 +81,9 @@ void ciface::Win32::PopulateDevices(void* hwnd) s_hwnd = static_cast(hwnd); std::lock_guard lk_population(s_populate_mutex); s_first_populate_devices_asked.Set(); +#if !_UWP ciface::DInput::PopulateDevices(s_hwnd); +#endif ciface::XInput::PopulateDevices(); ciface::WGInput::PopulateDevices(); } @@ -84,13 +92,17 @@ void ciface::Win32::ChangeWindow(void* hwnd) { s_hwnd = static_cast(hwnd); std::lock_guard lk_population(s_populate_mutex); +#if !_UWP ciface::DInput::ChangeWindow(s_hwnd); +#endif } void ciface::Win32::DeInit() { s_first_populate_devices_asked.Clear(); +#if !_UWP DInput::DeInit(); +#endif s_hwnd = nullptr; if (s_notify_handle) diff --git a/Source/Core/UICommon/DiscordPresence.cpp b/Source/Core/UICommon/DiscordPresence.cpp index ff0afb5d2565..bffcd74cdcc4 100644 --- a/Source/Core/UICommon/DiscordPresence.cpp +++ b/Source/Core/UICommon/DiscordPresence.cpp @@ -259,6 +259,7 @@ bool UpdateDiscordPresenceRaw(const std::string& details, const std::string& sta return true; #endif + return false; } void UpdateDiscordPresence(int party_size, SecretType type, const std::string& secret, diff --git a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp index bca820a2c3b3..f43d47542fa4 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Pipeline.cpp @@ -224,6 +224,7 @@ std::unique_ptr DXPipeline::Create(const AbstractPipelineConfig& con AbstractPipeline::CacheData DXPipeline::GetCacheData() const { +#if !_UWP ComPtr blob; HRESULT hr = m_pipeline->GetCachedBlob(&blob); if (FAILED(hr)) @@ -235,5 +236,9 @@ AbstractPipeline::CacheData DXPipeline::GetCacheData() const CacheData data(blob->GetBufferSize()); std::memcpy(data.data(), blob->GetBufferPointer(), blob->GetBufferSize()); return data; +#else + // Xbox's graphics driver under UWP does not support this feature. + return {}; +#endif } } // namespace DX12 diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp index a6abc9159f5f..f8062e0b2955 100644 --- a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp @@ -60,7 +60,12 @@ u32 SwapChain::GetSwapChainFlags() const bool SwapChain::CreateSwapChain(bool stereo) { RECT client_rc; - if (GetClientRect(static_cast(m_wsi.render_surface), &client_rc)) + if (m_wsi.type == WindowSystemType::UWP) + { + m_width = m_wsi.render_width; + m_height = m_wsi.render_height; + } + else if (GetClientRect(static_cast(m_wsi.render_surface), &client_rc)) { m_width = client_rc.right - client_rc.left; m_height = client_rc.bottom - client_rc.top; @@ -87,9 +92,19 @@ bool SwapChain::CreateSwapChain(bool stereo) swap_chain_desc.Flags = GetSwapChainFlags(); Microsoft::WRL::ComPtr swap_chain1; - hr = dxgi_factory2->CreateSwapChainForHwnd(m_d3d_device.Get(), - static_cast(m_wsi.render_surface), - &swap_chain_desc, nullptr, nullptr, &swap_chain1); + if (m_wsi.type == WindowSystemType::UWP) + { + hr = dxgi_factory2->CreateSwapChainForCoreWindow( + m_d3d_device.Get(), static_cast<::IUnknown*>(m_wsi.render_surface), &swap_chain_desc, + nullptr, &swap_chain1); + } + else + { + hr = dxgi_factory2->CreateSwapChainForHwnd(m_d3d_device.Get(), + static_cast(m_wsi.render_surface), + &swap_chain_desc, nullptr, nullptr, &swap_chain1); + } + if (FAILED(hr)) { // Flip-model discard swapchains aren't supported on Windows 8, so here we fall back to @@ -131,9 +146,13 @@ bool SwapChain::CreateSwapChain(bool stereo) return false; } - // We handle fullscreen ourselves. - hr = m_dxgi_factory->MakeWindowAssociation(static_cast(m_wsi.render_surface), - DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER); + if (m_wsi.type != WindowSystemType::UWP) + { + // We handle fullscreen ourselves. + hr = m_dxgi_factory->MakeWindowAssociation(static_cast(m_wsi.render_surface), + DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER); + } + if (FAILED(hr)) WARN_LOG_FMT(VIDEO, "MakeWindowAssociation() failed: {}", Common::HRWrap(hr)); diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 2b4883d22bc8..9e4849f8a837 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -224,8 +224,13 @@ const std::vector>& VideoBackendBase::GetAvail #endif #ifdef _WIN32 backends.push_back(std::make_unique()); +#if _UWP + // If on UWP, give D3D12 precedence as on the S/X, D3D11 is just a 'less supported' and wrapped version of D3D12. + backends.emplace(backends.begin(), std::make_unique()); +#else backends.push_back(std::make_unique()); #endif +#endif #ifdef __APPLE__ backends.push_back(std::make_unique()); #endif diff --git a/Source/VSProps/Base.Dolphin.props b/Source/VSProps/Base.Dolphin.props index 0cbbab961793..beef9d621089 100644 --- a/Source/VSProps/Base.Dolphin.props +++ b/Source/VSProps/Base.Dolphin.props @@ -35,16 +35,18 @@ _ARCH_64=1;_M_X86=1;_M_X86_64=1;%(PreprocessorDefinitions) _ARCH_64=1;_M_ARM_64=1;%(PreprocessorDefinitions) - USE_UPNP;__LIBUSB__;%(PreprocessorDefinitions) + USE_UPNP;%(PreprocessorDefinitions) + __LIBUSB__;%(PreprocessorDefinitions) USE_ANALYTICS=1;%(PreprocessorDefinitions) - USE_DISCORD_PRESENCE;%(PreprocessorDefinitions) + USE_DISCORD_PRESENCE;%(PreprocessorDefinitions) HAVE_FFMPEG;%(PreprocessorDefinitions) - HAS_OPENGL;%(PreprocessorDefinitions) - HAS_VULKAN;%(PreprocessorDefinitions) + HAS_OPENGL;%(PreprocessorDefinitions) + HAS_VULKAN;%(PreprocessorDefinitions) HAS_LIBMGBA;%(PreprocessorDefinitions) AUTOUPDATE;%(PreprocessorDefinitions) HAVE_SDL2;%(PreprocessorDefinitions) STEAM;%(PreprocessorDefinitions) + _UWP=1;%(PreprocessorDefinitions)