UWP improvements 2

This commit is contained in:
Bashar Astifan 2023-08-23 02:25:57 +04:00
parent fb80dcacf7
commit 04d72ebe54
21 changed files with 401 additions and 200 deletions

View file

@ -64,14 +64,10 @@ static EShLanguage GetShLanguageFromStage(const ShaderStage stage) {
void ShaderTranslationInit() {
// TODO: We have TLS issues on UWP
#if !PPSSPP_PLATFORM(UWP)
glslang::InitializeProcess();
#endif
}
void ShaderTranslationShutdown() {
#if !PPSSPP_PLATFORM(UWP)
glslang::FinalizeProcess();
#endif
}
struct Builtin {
@ -229,11 +225,6 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, const ShaderLan
return result;
}
#if PPSSPP_PLATFORM(UWP)
*errorMessage = "No shader translation available (UWP)";
return false;
#endif
errorMessage->clear();
glslang::TProgram program;

View file

@ -305,7 +305,7 @@ void PostLoadConfig() {
else
g_i18nrepo.LoadIni(g_Config.sLanguageIni, langOverridePath);
#if !PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
#if !PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(UWP)
CreateSysDirectories();
#endif
}

View file

@ -3,17 +3,20 @@
#include "pch.h"
#include "App.h"
#include <ppltasks.h>
#include <mutex>
#include "Common/Net/HTTPClient.h"
#include "Common/Net/Resolve.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Input/InputState.h"
#include "Common/System/NativeApp.h"
#include "Common/System/System.h"
#include "Common/LogManager.h"
#include "Core/System.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include <ppltasks.h>
#include "UWPHelpers/LaunchItem.h"
using namespace UWP;
@ -27,7 +30,6 @@ using namespace Windows::UI::Input;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
using namespace Windows::Storage;
// The main function is only used to initialize our IFrameworkView class.
[Platform::MTAThread]
@ -47,6 +49,50 @@ App::App() :
{
}
void App::InitialPPSSPP() {
// Initial net
net::Init();
//Prepare for initialization
std::wstring internalDataFolderW = ApplicationData::Current->LocalFolder->Path->Data();
g_Config.internalDataDirectory = Path(internalDataFolderW);
g_Config.memStickDirectory = g_Config.internalDataDirectory;
// On Win32 it makes more sense to initialize the system directories here
// because the next place it was called was in the EmuThread, and it's too late by then.
CreateSysDirectories();
LogManager::Init(&g_Config.bEnableLogging);
// Set the config path to local state by default
// it will be overrided by `NativeInit` if there is custom memStick
g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
g_Config.Load();
if (g_Config.bFirstRun) {
// Clear `memStickDirectory` to show memory stick screen on first start
g_Config.memStickDirectory.clear();
}
// Since we don't have any async operation in `NativeInit`
// it's better to call it here
const char* argv[2] = { "fake", nullptr };
std::string cacheFolder = ConvertWStringToUTF8(ApplicationData::Current->TemporaryFolder->Path->Data());
// Ee will not be able to use `argv`
// since launch parameters usually handled by `OnActivated`
// and `OnActivated` will be invoked later, even after `PPSSPP_UWPMain(..)`
// so we are handling launch cases using `LaunchItem`
NativeInit(1, argv, "", "", cacheFolder.c_str());
// Override backend, `DIRECT3D11` is the only way for UWP apps
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
// Calling `NativeInit` before will help us to deal with custom configs
// such as custom adapter, so it's better to initial render device here
m_deviceResources = std::make_shared<DX::DeviceResources>();
m_deviceResources->CreateWindowSizeDependentResources();
}
// The first method called when the IFrameworkView is being created.
void App::Initialize(CoreApplicationView^ applicationView) {
// Register event handlers for app lifecycle. This example includes Activated, so that we
@ -59,10 +105,6 @@ void App::Initialize(CoreApplicationView^ applicationView) {
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &App::OnResuming);
// At this point we have access to the device.
// We can create the device-dependent resources.
m_deviceResources = std::make_shared<DX::DeviceResources>();
}
// Called when the CoreWindow object is created (or re-created).
@ -89,6 +131,7 @@ void App::SetWindow(CoreWindow^ window) {
window->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &App::OnKeyDown);
window->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &App::OnKeyUp);
window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &App::OnCharacterReceived);
window->PointerMoved += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerMoved);
window->PointerEntered += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerEntered);
@ -111,7 +154,7 @@ void App::SetWindow(CoreWindow^ window) {
Windows::UI::Core::BackRequestedEventArgs^>(
this, &App::App_BackRequested);
m_deviceResources->SetWindow(window);
InitialPPSSPP();
}
bool App::HasBackButton() {
@ -137,6 +180,10 @@ void App::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyE
m_main->OnKeyUp(args->KeyStatus.ScanCode, args->VirtualKey);
}
void App::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args) {
m_main->OnCharacterReceived(args->KeyStatus.ScanCode, args->KeyCode);
}
void App::OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
int pointerId = touchMap_.TouchId(args->CurrentPoint->PointerId);
if (pointerId < 0)

View file

@ -84,6 +84,7 @@ namespace UWP {
// Input
void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args);
void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerEntered(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
@ -94,6 +95,7 @@ namespace UWP {
void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void App_BackRequested(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ e);
void InitialPPSSPP();
private:
std::shared_ptr<DX::DeviceResources> m_deviceResources;

View file

@ -3,6 +3,10 @@
#include "DeviceResources.h"
#include "DirectXHelper.h"
#include "Core/Config.h"
#include "Common/StringUtils.h"
#include "Common/Data/Encoding/Utf8.h"
using namespace D2D1;
using namespace DirectX;
using namespace Microsoft::WRL;
@ -125,7 +129,7 @@ void DX::DeviceResources::CreateDeviceIndependentResources()
}
// Configures the Direct3D device, and stores handles to it and the device context.
void DX::DeviceResources::CreateDeviceResources()
void DX::DeviceResources::CreateDeviceResources(IDXGIAdapter* vAdapter)
{
// This flag adds support for surfaces with a different color channel ordering
// than the API default. It is required for compatibility with Direct2D.
@ -159,10 +163,10 @@ void DX::DeviceResources::CreateDeviceResources()
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
auto hardwareType = (vAdapter != nullptr ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE);
HRESULT hr = D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver.
vAdapter, // Specify nullptr to use the default adapter.
hardwareType, // Create a device using the hardware graphics driver.
0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
creationFlags, // Set debug and Direct2D compatibility flags.
featureLevels, // List of feature levels this app can support.
@ -194,6 +198,14 @@ void DX::DeviceResources::CreateDeviceResources()
);
}
if (!vAdapter && CreateAdaptersList(device)) {
// While fetching the adapters list
// we will check if the configs has custom adapter
// then will recall this function to create device with custom adapter
// so we have to stop here, if the `CreateAdaptersList` return true
return;
}
// Store pointers to the Direct3D 11.3 API device and immediate context.
DX::ThrowIfFailed(
device.As(&m_d3dDevice)
@ -203,14 +215,25 @@ void DX::DeviceResources::CreateDeviceResources()
context.As(&m_d3dContext)
);
// Create the Direct2D device object and a corresponding context.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
m_d3dDevice.As(&m_dxgiDevice)
);
DX::ThrowIfFailed(
m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
m_dxgiDevice->GetAdapter(&m_dxgiAdapter)
);
DX::ThrowIfFailed(
m_dxgiAdapter->GetParent(IID_PPV_ARGS(&m_dxgiFactory))
);
// Create the Direct2D device object and a corresponding context.
DX::ThrowIfFailed(
m_d3dDevice.As(&m_dxgiDevice)
);
DX::ThrowIfFailed(
m_d2dFactory->CreateDevice(m_dxgiDevice.Get(), &m_d2dDevice)
);
DX::ThrowIfFailed(
@ -221,9 +244,53 @@ void DX::DeviceResources::CreateDeviceResources()
);
}
bool DX::DeviceResources::CreateAdaptersList(ComPtr<ID3D11Device> device) {
ComPtr<IDXGIDevice3> dxgi_device;
DX::ThrowIfFailed(
device.As(&dxgi_device)
);
Microsoft::WRL::ComPtr<IDXGIAdapter> deviceAdapter;
dxgi_device->GetAdapter(&deviceAdapter);
Microsoft::WRL::ComPtr<IDXGIFactory4> deviceFactory;
deviceAdapter->GetParent(IID_PPV_ARGS(&deviceFactory));
UINT i = 0;
IDXGIAdapter* pAdapter;
IDXGIAdapter* customAdapter = nullptr;
while (deviceFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC vAdapterDesc;
pAdapter->GetDesc(&vAdapterDesc);
auto adapterDescription = ConvertWStringToUTF8(vAdapterDesc.Description);
m_vAdapters.push_back(adapterDescription);
if (g_Config.sD3D11Device == adapterDescription) {
customAdapter = pAdapter;
}
++i;
}
deviceFactory->Release();
bool reCreateDevice = false;
if (customAdapter) {
reCreateDevice = true;
// Recreate device with custom adapter
CreateDeviceResources(customAdapter);
}
return reCreateDevice;
}
// These resources need to be recreated every time the window size is changed.
void DX::DeviceResources::CreateWindowSizeDependentResources()
{
// Window pointer was previously submited by `SetWindow` called from (App.cpp)
// we don't have to do that since we can easily get the current window
auto coreWindow = CoreWindow::GetForCurrentThread();
SetWindow(coreWindow);
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = {nullptr};
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
@ -287,27 +354,11 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
swapChainDesc.Scaling = scaling;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
// This sequence obtains the DXGI factory that was used to create the Direct3D device above.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory4> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
);
ComPtr<IDXGISwapChain1> swapChain;
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForCoreWindow(
m_dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(m_window.Get()),
reinterpret_cast<IUnknown*>(coreWindow),
&swapChainDesc,
nullptr,
&swapChain
@ -320,7 +371,7 @@ void DX::DeviceResources::CreateWindowSizeDependentResources()
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
DX::ThrowIfFailed(
dxgiDevice->SetMaximumFrameLatency(1)
m_dxgiDevice->SetMaximumFrameLatency(1)
);
}
@ -461,7 +512,6 @@ void DX::DeviceResources::SetWindow(CoreWindow^ window)
{
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
m_window = window;
if (Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily == L"Windows.Xbox")
{
const auto hdi = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
@ -494,8 +544,6 @@ void DX::DeviceResources::SetWindow(CoreWindow^ window)
m_currentOrientation = currentDisplayInformation->CurrentOrientation;
m_d2dContext->SetDpi(m_dpi, m_dpi);
CreateWindowSizeDependentResources();
}
// This method is called in the event handler for the SizeChanged event.
@ -515,10 +563,8 @@ void DX::DeviceResources::SetDpi(float dpi)
{
m_dpi = dpi;
// When the display DPI changes, the logical size of the window (measured in Dips) also changes and needs to be updated.
m_logicalSize = Windows::Foundation::Size(m_window->Bounds.Width, m_window->Bounds.Height);
m_d2dContext->SetDpi(m_dpi, m_dpi);
// When the display DPI changes, the logical size of the window (measured in Dips)
// also changes and needs to be updated.
CreateWindowSizeDependentResources();
}
}
@ -540,18 +586,8 @@ void DX::DeviceResources::ValidateDevice()
// was created or if the device has been removed.
// First, get the information for the default adapter from when the device was created.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
ComPtr<IDXGIAdapter> deviceAdapter;
DX::ThrowIfFailed(dxgiDevice->GetAdapter(&deviceAdapter));
ComPtr<IDXGIFactory4> deviceFactory;
DX::ThrowIfFailed(deviceAdapter->GetParent(IID_PPV_ARGS(&deviceFactory)));
ComPtr<IDXGIAdapter1> previousDefaultAdapter;
DX::ThrowIfFailed(deviceFactory->EnumAdapters1(0, &previousDefaultAdapter));
DX::ThrowIfFailed(m_dxgiFactory->EnumAdapters1(0, &previousDefaultAdapter));
DXGI_ADAPTER_DESC1 previousDesc;
DX::ThrowIfFailed(previousDefaultAdapter->GetDesc1(&previousDesc));
@ -575,9 +611,6 @@ void DX::DeviceResources::ValidateDevice()
FAILED(m_d3dDevice->GetDeviceRemovedReason()))
{
// Release references to resources related to the old device.
dxgiDevice = nullptr;
deviceAdapter = nullptr;
deviceFactory = nullptr;
previousDefaultAdapter = nullptr;
// Create a new device and swap chain.

View file

@ -1,4 +1,7 @@
#pragma once
#pragma once
#include <vector>
#include <string>
namespace DX
{
@ -14,6 +17,7 @@ namespace DX
{
public:
DeviceResources();
void CreateWindowSizeDependentResources();
void SetWindow(Windows::UI::Core::CoreWindow^ window);
void SetLogicalSize(Windows::Foundation::Size logicalSize);
void SetCurrentOrientation(Windows::Graphics::Display::DisplayOrientations currentOrientation);
@ -52,16 +56,24 @@ namespace DX
DXGI_MODE_ROTATION ComputeDisplayRotation();
std::vector <std::string> GetAdapters() const { return m_vAdapters; };
private:
void CreateDeviceIndependentResources();
void CreateDeviceResources();
void CreateWindowSizeDependentResources();
void CreateDeviceResources(IDXGIAdapter* vAdapter = nullptr);
void UpdateRenderTargetSize();
bool CreateAdaptersList(Microsoft::WRL::ComPtr<ID3D11Device> device);
// Direct3D objects.
Microsoft::WRL::ComPtr<ID3D11Device3> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext3> m_d3dContext;
Microsoft::WRL::ComPtr<IDXGISwapChain3> m_swapChain;
Microsoft::WRL::ComPtr<IDXGIDevice3> m_dxgiDevice;
Microsoft::WRL::ComPtr<IDXGIFactory4> m_dxgiFactory;
Microsoft::WRL::ComPtr<IDXGIAdapter> m_dxgiAdapter;
// Direct3D adapters
std::vector <std::string> m_vAdapters;
// Direct3D rendering objects. Required for 3D.
Microsoft::WRL::ComPtr<ID3D11RenderTargetView1> m_d3dRenderTargetView;
@ -77,9 +89,6 @@ namespace DX
Microsoft::WRL::ComPtr<IDWriteFactory3> m_dwriteFactory;
Microsoft::WRL::ComPtr<IWICImagingFactory2> m_wicFactory;
// Cached reference to the Window.
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
// Cached device properties.
D3D_FEATURE_LEVEL m_d3dFeatureLevel;
Windows::Foundation::Size m_d3dRenderTargetSize;

View file

@ -73,6 +73,7 @@ std::map<Windows::System::VirtualKey, InputKeyCode> virtualKeyCodeToNKCode{
{ VirtualKey::PageUp, NKCODE_PAGE_UP },
{ VirtualKey::PageDown, NKCODE_PAGE_DOWN },
{ VirtualKey::Delete, NKCODE_FORWARD_DEL },
{ VirtualKey::Back, NKCODE_DEL },
{ VirtualKey::End, NKCODE_MOVE_END },
{ VirtualKey::Tab, NKCODE_TAB },
{ VirtualKey::Down, NKCODE_DPAD_DOWN },

View file

@ -25,7 +25,7 @@
#include "Common/System/Display.h"
#include "Common/System/NativeApp.h"
#include "Common/System/Request.h"
#include <Common/OSVersion.h>
#include "Common/OSVersion.h"
#include "Core/System.h"
#include "Core/Loaders.h"
@ -38,10 +38,11 @@
#include "UWPUtil.h"
#include "App.h"
// UWP Storage helper includes
// UWP Helpers includes
#include "UWPHelpers/StorageManager.h"
#include "UWPHelpers/StorageAsync.h"
#include "UWPHelpers/LaunchItem.h"
#include <UWPHelpers/InputHelpers.h>
using namespace UWP;
using namespace Windows::Foundation;
@ -53,9 +54,7 @@ using namespace Windows::Devices::Enumeration;
using namespace Concurrency;
// UGLY!
PPSSPP_UWPMain *g_main;
extern WindowsAudioBackend *winAudioBackend;
std::string langRegion;
std::list<std::unique_ptr<InputDevice>> g_input;
// TODO: Use Microsoft::WRL::ComPtr<> for D3D11 objects?
@ -67,87 +66,29 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptr<DX::DeviceResourc
app_(app),
m_deviceResources(deviceResources)
{
g_main = this;
net::Init();
// Register to be notified if the Device is lost or recreated
m_deviceResources->RegisterDeviceNotify(this);
// create_task(KnownFolders::GetFolderForUserAsync(nullptr, KnownFolderId::RemovableDevices)).then([this](StorageFolder ^));
// TODO: Change the timer settings if you want something other than the default variable timestep mode.
// e.g. for 60 FPS fixed timestep update logic, call:
/*
m_timer.SetFixedTimeStep(true);
m_timer.SetTargetElapsedSeconds(1.0 / 60);
*/
ctx_.reset(new UWPGraphicsContext(deviceResources));
const Path &exePath = File::GetExeDirectory();
// Get install location
auto packageDirectory = Package::Current->InstalledPath;
const Path &exePath = Path(FromPlatformString(packageDirectory));
g_VFS.Register("", new DirectoryReader(exePath / "Content"));
g_VFS.Register("", new DirectoryReader(exePath));
wchar_t lcCountry[256];
if (0 != GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256)) {
langRegion = ConvertWStringToUTF8(lcCountry);
for (size_t i = 0; i < langRegion.size(); i++) {
if (langRegion[i] == '-')
langRegion[i] = '_';
}
} else {
langRegion = "en_US";
}
std::wstring internalDataFolderW = ApplicationData::Current->LocalFolder->Path->Data();
g_Config.internalDataDirectory = Path(internalDataFolderW);
g_Config.memStickDirectory = g_Config.internalDataDirectory;
// Mount a filesystem
g_Config.flash0Directory = exePath / "assets/flash0";
// On Win32 it makes more sense to initialize the system directories here
// because the next place it was called was in the EmuThread, and it's too late by then.
CreateSysDirectories();
LogManager::Init(&g_Config.bEnableLogging);
// Load config up here, because those changes below would be overwritten
// if it's not loaded here first.
g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
g_Config.Load();
if (g_Config.bFirstRun) {
g_Config.memStickDirectory.clear();
}
bool debugLogLevel = false;
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
if (debugLogLevel) {
#if _DEBUG
LogManager::GetInstance()->SetAllLogLevels(LogTypes::LDEBUG);
}
// Set log file location
if (g_Config.bEnableLogging) {
LogManager::GetInstance()->ChangeFileLog(GetLogFile().c_str());
}
#endif
const char *argv[2] = { "fake", nullptr };
int argc = 1;
std::string cacheFolder = ConvertWStringToUTF8(ApplicationData::Current->TemporaryFolder->Path->Data());
// 'PPSSPP_UWPMain' is getting called before 'OnActivated'
// this make detecting launch items on startup hard
// I think 'Init' process must be moved out and invoked from 'OnActivated' one time only
// currently launchItem will work fine but we cannot skip logo screen
// we should pass file path to 'argv' using 'GetLaunchItemPath(args)'
// instead of depending on 'boot_filename' (LaunchItem.cpp)
NativeInit(argc, argv, "", "", cacheFolder.c_str());
// At this point we have main requirements initialized (Log, Config, NativeInit, Device)
NativeInitGraphics(ctx_.get());
NativeResized();
@ -185,15 +126,10 @@ void PPSSPP_UWPMain::CreateWindowSizeDependentResources() {
ctx_->GetDrawContext()->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, m_deviceResources->GetBackBufferRenderTargetView());
}
// Renders the current frame according to the current application state.
// Returns true if the frame was rendered and is ready to be displayed.
bool PPSSPP_UWPMain::Render() {
static bool hasSetThreadName = false;
if (!hasSetThreadName) {
SetCurrentThreadName("UWPRenderThread");
hasSetThreadName = true;
}
void PPSSPP_UWPMain::UpdateScreenState() {
// This code was included into the render loop directly
// based on my test I don't understand why it should be called each loop
// is it better to call it on demand only, like when screen state changed?
auto context = m_deviceResources->GetD3DDeviceContext();
switch (m_deviceResources->ComputeDisplayRotation()) {
@ -232,6 +168,18 @@ bool PPSSPP_UWPMain::Render() {
g_display.dp_yres = g_display.pixel_yres * g_display.dpi_scale_y;
context->RSSetViewports(1, &viewport);
}
// Renders the current frame according to the current application state.
// Returns true if the frame was rendered and is ready to be displayed.
bool PPSSPP_UWPMain::Render() {
static bool hasSetThreadName = false;
if (!hasSetThreadName) {
SetCurrentThreadName("UWPRenderThread");
hasSetThreadName = true;
}
UpdateScreenState();
NativeFrame(ctx_.get());
return true;
@ -271,6 +219,17 @@ void PPSSPP_UWPMain::OnKeyUp(int scanCode, Windows::System::VirtualKey virtualKe
}
}
void PPSSPP_UWPMain::OnCharacterReceived(int scanCode, unsigned int keyCode) {
// TODO: Once on-screen keyboard show/hide solved, add `InputPaneVisible()` as extra condition
if (!PSP_IsInited() && !IsCtrlOnHold()) {
KeyInput key{};
key.deviceId = DEVICE_ID_KEYBOARD;
key.keyCode = (InputKeyCode)keyCode;
key.flags = KEY_DOWN | KEY_CHAR;
NativeKey(key);
}
}
void PPSSPP_UWPMain::OnMouseWheel(float delta) {
InputKeyCode key = NKCODE_EXT_MOUSEWHEEL_UP;
if (delta < 0) {
@ -335,7 +294,7 @@ void PPSSPP_UWPMain::OnSuspend() {
UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) {
std::vector<std::string> adapterNames;
std::vector<std::string> adapterNames = resources->GetAdapters();
draw_ = Draw::T3DCreateD3D11Context(
resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetD3DDevice(), resources->GetD3DDeviceContext(), resources->GetSwapChain(), resources->GetDeviceFeatureLevel(), 0, adapterNames, g_Config.iInflightFrames);
@ -353,7 +312,7 @@ std::string System_GetProperty(SystemProperty prop) {
case SYSPROP_NAME:
return GetWindowsVersion();
case SYSPROP_LANGREGION:
return langRegion;
return GetLangRegion();
case SYSPROP_CLIPBOARD_TEXT:
/* TODO: Need to either change this API or do this on a thread in an ugly fashion.
DataPackageView ^view = Clipboard::GetContent();
@ -412,13 +371,17 @@ int System_GetPropertyInt(SystemProperty prop) {
case SYSPROP_DISPLAY_XRES:
{
CoreWindow^ corewindow = CoreWindow::GetForCurrentThread();
if (corewindow) {
return (int)corewindow->Bounds.Width;
}
}
case SYSPROP_DISPLAY_YRES:
{
CoreWindow^ corewindow = CoreWindow::GetForCurrentThread();
if (corewindow) {
return (int)corewindow->Bounds.Height;
}
}
default:
return -1;
}
@ -464,7 +427,12 @@ bool System_GetPropertyBool(SystemProperty prop) {
case SYSPROP_CAN_JIT:
return true;
case SYSPROP_HAS_KEYBOARD:
return true;
{
// Do actual check
// touch devices has input pane, we need to depend on it
// I don't know any possible way to display input dialog in non-xaml apps
return isKeybaordAvailable() || isTouchAvailable();
}
default:
return false;
}
@ -576,6 +544,24 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
if (!param1.empty() && !strcmp(param1.c_str(), "menu")) {
CloseLaunchItem();
}
else if (!strcmp(param1.c_str(), "show_keyboard")) {
// Must be performed from UI thread
Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([]()
{
ShowInputPane();
}));
}
else if (!strcmp(param1.c_str(), "hide_keyboard")) {
// Must be performed from UI thread
Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([]()
{
HideInputPane();
}));
}
return true;
}
case SystemRequestType::COPY_TO_CLIPBOARD:
@ -695,20 +681,3 @@ std::string GetCPUBrandString() {
return "Unknown";
}
}
// Emulation of TlsAlloc for Windows 10. Used by glslang. Doesn't actually seem to work, other than fixing the linking errors?
extern "C" {
DWORD WINAPI __imp_TlsAlloc() {
return FlsAlloc(nullptr);
}
BOOL WINAPI __imp_TlsFree(DWORD index) {
return FlsFree(index);
}
BOOL WINAPI __imp_TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
return FlsSetValue(dwTlsIndex, lpTlsValue);
}
LPVOID WINAPI __imp_TlsGetValue(DWORD dwTlsIndex) {
return FlsGetValue(dwTlsIndex);
}
}

View file

@ -34,6 +34,7 @@ public:
PPSSPP_UWPMain(App ^app, const std::shared_ptr<DX::DeviceResources>& deviceResources);
~PPSSPP_UWPMain();
void CreateWindowSizeDependentResources();
void UpdateScreenState();
bool Render();
// IDeviceNotify
@ -44,6 +45,7 @@ public:
// Not sure whether this abstraction is worth it.
void OnKeyDown(int scanCode, Windows::System::VirtualKey virtualKey, int repeatCount);
void OnKeyUp(int scanCode, Windows::System::VirtualKey virtualKey);
void OnCharacterReceived(int scanCode,unsigned int keyCode);
void OnTouchEvent(int touchEvent, int touchId, float x, float y, double timestamp);
@ -57,8 +59,6 @@ public:
void OnSuspend();
void Close();
void LoadStorageFile(Windows::Storage::StorageFile ^file);
private:
App ^app_;

View file

@ -1,6 +1,6 @@
<?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" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap">
<Identity Name="0ad29e1a-1069-4cf5-8c97-620892505f0c" Publisher="CN=Henrik" Version="1.15.4.0" />
<Identity Name="0ad29e1a-1069-4cf5-8c97-620892505f0c" Publisher="CN=Henrik" Version="1.16.0.0" />
<mp:PhoneIdentity PhoneProductId="0ad29e1a-1069-4cf5-8c97-620892505f0c" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>PPSSPP - PSP emulator</DisplayName>

View file

@ -1,6 +1,6 @@
<?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" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap">
<Identity Name="32617401-c880-44d1-ba5a-c0b46feba525" Publisher="CN=Henrik" Version="1.15.4.0" />
<Identity Name="32617401-c880-44d1-ba5a-c0b46feba525" Publisher="CN=Henrik" Version="1.16.0.0" />
<mp:PhoneIdentity PhoneProductId="32617401-c880-44d1-ba5a-c0b46feba525" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>PPSSPP Gold - PSP emulator</DisplayName>

View file

@ -1,6 +1,6 @@
<?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" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap">
<Identity Name="0ad29e1a-1069-4cf5-8c97-620892505f0c" Publisher="CN=Henrik" Version="1.15.4.0" />
<Identity Name="0ad29e1a-1069-4cf5-8c97-620892505f0c" Publisher="CN=Henrik" Version="1.16.0.0" />
<mp:PhoneIdentity PhoneProductId="0ad29e1a-1069-4cf5-8c97-620892505f0c" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>PPSSPP - PSP emulator</DisplayName>

View file

@ -77,7 +77,6 @@
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<AppxBundle>Never</AppxBundle>
<PackageCertificateThumbprint>C8DEB388B9BC89D1DC61324E4E9D9FE6A796B7AA</PackageCertificateThumbprint>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppInstallerUpdateFrequency>0</AppInstallerUpdateFrequency>
<AppInstallerCheckForUpdateFrequency>OnApplicationRun</AppInstallerCheckForUpdateFrequency>
@ -372,6 +371,7 @@
<ClInclude Include="PPSSPP_UWPMain.h" />
<ClInclude Include="Common\DirectXHelper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="UWPHelpers\InputHelpers.h" />
<ClInclude Include="UWPUtil.h" />
<ClInclude Include="XAudioSoundStream.h" />
<ClInclude Include="UWPHelpers\StorageAccess.h" />
@ -398,6 +398,7 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="UWPHelpers\InputHelpers.cpp" />
<ClCompile Include="XAudioSoundStream.cpp" />
</ItemGroup>
<ItemGroup>

View file

@ -126,6 +126,9 @@
<ClCompile Include="UWPHelpers\LaunchItem.cpp">
<Filter>UWPHelpers</Filter>
</ClCompile>
<ClCompile Include="UWPHelpers\InputHelpers.cpp">
<Filter>UWPHelpers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="App.h" />
@ -145,6 +148,9 @@
<ClInclude Include="..\Windows\InputDevice.h">
<Filter>Input</Filter>
</ClInclude>
<ClInclude Include="UWPHelpers\InputHelpers.h">
<Filter>UWPHelpers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="Assets\StoreLogo.png">

View file

@ -0,0 +1,95 @@
// Copyright (c) 2023- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "InputHelpers.h"
#include "UWPUtil.h"
#include "NKCodeFromWindowsSystem.h"
#include "Common/Log.h"
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::ViewManagement;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Data::Xml::Dom;
using namespace Windows::UI::Notifications;
#pragma region Input Keyboard
bool isKeybaordAvailable() {
Windows::Devices::Input::KeyboardCapabilities^ keyboardCapabilities = ref new Windows::Devices::Input::KeyboardCapabilities();
bool hasKeyboard = keyboardCapabilities->KeyboardPresent != 0;
return hasKeyboard;
}
bool isTouchAvailable() {
Windows::Devices::Input::TouchCapabilities^ touchCapabilities = ref new Windows::Devices::Input::TouchCapabilities();
bool hasTouch = touchCapabilities->TouchPresent != 0;
return hasTouch;
}
bool keyboardVisible = false;
bool InputPaneVisible() {
return keyboardVisible;
}
void ShowInputPane() {
VERBOSE_LOG(COMMON, "ShowInputKeyboard");
InputPane::GetForCurrentView()->TryShow();
keyboardVisible = true;
}
void HideInputPane() {
VERBOSE_LOG(COMMON, "HideInputKeyboard");
InputPane::GetForCurrentView()->TryHide();
keyboardVisible = false;
}
#pragma endregion
#pragma region Keys Status
bool IsCapsLockOn() {
auto capsLockState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::CapitalLock);
return (capsLockState == CoreVirtualKeyStates::Locked);
}
bool IsShiftOnHold() {
auto shiftState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::Shift);
return (shiftState == CoreVirtualKeyStates::Down);
}
bool IsCtrlOnHold() {
auto ctrlState = CoreApplication::MainView->CoreWindow->GetKeyState(VirtualKey::Control);
return (ctrlState == CoreVirtualKeyStates::Down);
}
#pragma endregion
#pragma region Misc
std::string GetLangRegion() {
std::string langRegion = "en_US";
wchar_t lcCountry[256];
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, lcCountry, 256) != FALSE) {
langRegion = ConvertWStringToUTF8(lcCountry);
for (size_t i = 0; i < langRegion.size(); i++) {
if (langRegion[i] == '-')
langRegion[i] = '_';
}
}
return langRegion;
}
#pragma endregion

View file

@ -0,0 +1,37 @@
// Copyright (c) 2023- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string>
// Input Devices
bool isKeybaordAvailable();
bool isTouchAvailable();
// Input Pane
bool InputPaneVisible();
void ShowInputPane();
void HideInputPane();
// Keys Status
bool IsCapsLockOn();
bool IsShiftOnHold();
bool IsCtrlOnHold();
// Misc
std::string GetLangRegion();

View file

@ -21,18 +21,15 @@
#include <regex>
#include "LaunchItem.h"
#include "StorageAccess.h"
#include "Common/Log.h"
#include <Common/System/System.h>
#include <Common/File/Path.h>
#include "Common/System/System.h"
#include "Common/File/Path.h"
#include "UWPUtil.h"
extern void AddItemToFutureList(IStorageItem^ item);
// Temporary to handle startup items
// See remarks at 'PPSSPP_UWPMain.cpp', above 'NativeInit(..)'
extern Path boot_filename;
#include <ppl.h>
#include <ppltasks.h>
#pragma region LaunchItemClass
class LaunchItem {
@ -93,10 +90,13 @@ public:
void Start() {
if (IsValid()) {
concurrency::create_task([&] {
SetState(true);
std::string path = GetFilePath();
// Delay to be able to launch on startup too
std::this_thread::sleep_for(std::chrono::milliseconds(100));
System_PostUIMessage("boot", path.c_str());
boot_filename = Path(path); // Temporary to handle startup items
});
}
}
@ -135,7 +135,6 @@ public:
}
}
launchOnExit = std::string();
boot_filename.clear(); // Temporary to handle startup items
}
private:

View file

@ -21,7 +21,6 @@
#include "Common/File/Path.h"
using namespace Platform;
using namespace Windows::Storage;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Storage::AccessCache;

View file

@ -15,12 +15,18 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// This header meant to be included within the storage manager
// don't use it within PPSSPP core
#pragma once
#include <list>
#include <string>
using namespace Windows::Storage;
// Local settings
std::string GetDataFromLocalSettings(std::string key);
bool AddDataToLocalSettings(std::string key, std::string data, bool replace);
void AddItemToFutureList(IStorageItem^ item);
std::list<std::string> GetFutureAccessList();

View file

@ -87,7 +87,7 @@ std::string GetMusicFolder() {
std::string GetPreviewPath(std::string path) {
std::string pathView = path;
pathView = ReplaceAll(pathView, "/", "\\");
std::string currentMemoryStick = ConvertWStringToUTF8(g_Config.memStickDirectory.ToWString());
std::string currentMemoryStick = GetPSPFolder();
// Ensure memStick sub path replaced by 'ms:'
pathView = ReplaceAll(pathView, currentMemoryStick + "\\", "ms:\\");
auto appData = ReplaceAll(GetLocalFolder(), "\\LocalState", "");
@ -349,6 +349,13 @@ bool OpenFolder(std::string path) {
bool GetDriveFreeSpace(Path path, int64_t& space) {
bool state = false;
if (path.empty()) {
// This case happen on first start only
path = Path(GetPSPFolder());
if (g_Config.memStickDirectory.empty()) {
g_Config.memStickDirectory = path;
}
}
Platform::String^ wString = ref new Platform::String(path.ToWString().c_str());
StorageFolder^ storageItem;
ExecuteTask(storageItem, StorageFolder::GetFolderFromPathAsync(wString));
@ -377,7 +384,7 @@ bool GetDriveFreeSpace(Path path, int64_t& space) {
#pragma region Logs
std::string GetLogFile() {
std::string logFile;
Path logFilePath = Path(GetPSPFolder() + "\\PSP\\ppsspp.txt");
Path logFilePath = Path(GetPSPFolder() + "\\PSP\\ppsspplog.txt");
HANDLE h = CreateFile2FromAppW(logFilePath.ToWString().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);
if (h != INVALID_HANDLE_VALUE) {
logFile = logFilePath.ToString();

View file

@ -19,10 +19,9 @@
#include <list>
#include <set>
#include <string>
#include "Common/File/DirListing.h"
#include "StorageAccess.h"
#include "StoragePickers.h"
// Locations