git: d6b20717232e - main - emulators/duckstation: Update to 20231209

From: Ganael LAPLANCHE <martymac_at_FreeBSD.org>
Date: Mon, 18 Dec 2023 11:20:02 UTC
The branch main has been updated by martymac:

URL: https://cgit.FreeBSD.org/ports/commit/?id=d6b20717232e6200f9c60856d5761c85ddab88e9

commit d6b20717232e6200f9c60856d5761c85ddab88e9
Author:     Ganael LAPLANCHE <martymac@FreeBSD.org>
AuthorDate: 2023-12-18 11:19:30 +0000
Commit:     Ganael LAPLANCHE <martymac@FreeBSD.org>
CommitDate: 2023-12-18 11:19:30 +0000

    emulators/duckstation: Update to 20231209
---
 emulators/duckstation/Makefile                |   5 +-
 emulators/duckstation/distinfo                |   6 +-
 emulators/duckstation/files/patch-407049c.txt |  89 -------
 emulators/duckstation/files/patch-5246252.txt | 369 --------------------------
 emulators/duckstation/files/patch-5486a7a.txt |  30 ---
 emulators/duckstation/files/patch-af046c8.txt |  25 --
 emulators/duckstation/files/patch-b6d6756.txt |  34 ---
 emulators/duckstation/pkg-plist               |   1 +
 8 files changed, 6 insertions(+), 553 deletions(-)

diff --git a/emulators/duckstation/Makefile b/emulators/duckstation/Makefile
index 0a7a09f50cbb..c67ded9cb4d7 100644
--- a/emulators/duckstation/Makefile
+++ b/emulators/duckstation/Makefile
@@ -1,7 +1,6 @@
 PORTNAME=	duckstation
-PORTVERSION=	20231124
+PORTVERSION=	20231209
 DISTVERSIONPREFIX=	v
-PORTREVISION=	1
 CATEGORIES=	emulators
 
 MAINTAINER=	martymac@FreeBSD.org
@@ -28,7 +27,7 @@ USES=		cmake compiler:c++20-lang gl pkgconfig qt:6 sdl xorg
 USE_GITHUB=	yes
 GH_ACCOUNT=	stenzek
 # See: https://github.com/stenzek/duckstation/commits/latest
-GH_TAGNAME=	2739794
+GH_TAGNAME=	a9ee2a3
 
 USE_GL=		egl
 USE_SDL=	sdl2
diff --git a/emulators/duckstation/distinfo b/emulators/duckstation/distinfo
index 850ca8bcc01e..f458fb836a06 100644
--- a/emulators/duckstation/distinfo
+++ b/emulators/duckstation/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1701196143
-SHA256 (stenzek-duckstation-v20231124-2739794_GH0.tar.gz) = 19aeb00b3e56f5c34bccc6829b85141e47742d7c9314de6141c909c91d921542
-SIZE (stenzek-duckstation-v20231124-2739794_GH0.tar.gz) = 13558980
+TIMESTAMP = 1702583549
+SHA256 (stenzek-duckstation-v20231209-a9ee2a3_GH0.tar.gz) = 610605653748f30769beeb0aed3ec4f732220020f21ba25243a476f359305e39
+SIZE (stenzek-duckstation-v20231209-a9ee2a3_GH0.tar.gz) = 13678691
diff --git a/emulators/duckstation/files/patch-407049c.txt b/emulators/duckstation/files/patch-407049c.txt
deleted file mode 100644
index d07843895516..000000000000
--- a/emulators/duckstation/files/patch-407049c.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-Backport 407049c from upstream
-
-commit 407049cd91b65c8a917533b87c7264dba3e2adc5
-Author: Stenzek <stenzek@gmail.com>
-Date:   Tue Dec 5 15:21:52 2023 +1000
-
-    Qt: Resolve any symbolic links in AppRoot/DataRoot
-    
-    Should fix incorrect relative path generation on FreeBSD, where /home is
-    a symlink to /usr/home.
-
-diff --git a/src/duckstation-nogui/nogui_host.cpp b/src/duckstation-nogui/nogui_host.cpp
-index 8e2778ed..15ce8ae5 100644
---- src/duckstation-nogui/nogui_host.cpp
-+++ src/duckstation-nogui/nogui_host.cpp
-@@ -147,7 +147,7 @@ bool NoGUIHost::ShouldUsePortableMode()
- 
- void NoGUIHost::SetAppRoot()
- {
--  std::string program_path(FileSystem::GetProgramPath());
-+  const std::string program_path = FileSystem::GetProgramPath();
-   Log_InfoPrintf("Program Path: %s", program_path.c_str());
- 
-   EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
-@@ -190,7 +190,7 @@ void NoGUIHost::SetDataDirectory()
-   const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
-   if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
-   {
--    EmuFolders::DataRoot = Path::Combine(xdg_config_home, "duckstation");
-+    EmuFolders::DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "duckstation"));
-   }
-   else
-   {
-@@ -203,14 +203,14 @@ void NoGUIHost::SetDataDirectory()
-       const std::string share_dir(Path::Combine(local_dir, "share"));
-       FileSystem::EnsureDirectoryExists(local_dir.c_str(), false);
-       FileSystem::EnsureDirectoryExists(share_dir.c_str(), false);
--      EmuFolders::DataRoot = Path::Combine(share_dir, "duckstation");
-+      EmuFolders::DataRoot = Path::RealPath(Path::Combine(share_dir, "duckstation"));
-     }
-   }
- #elif defined(__APPLE__)
-   static constexpr char MAC_DATA_DIR[] = "Library/Application Support/DuckStation";
-   const char* home_dir = getenv("HOME");
-   if (home_dir)
--    EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR);
-+    EmuFolders::DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
- #endif
- 
-   // make sure it exists
-diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp
-index b7977cb6..9a52689c 100644
---- src/duckstation-qt/qthost.cpp
-+++ src/duckstation-qt/qthost.cpp
-@@ -252,7 +252,7 @@ bool QtHost::ShouldUsePortableMode()
- 
- void QtHost::SetAppRoot()
- {
--  std::string program_path(FileSystem::GetProgramPath());
-+  const std::string program_path = FileSystem::GetProgramPath();
-   Log_InfoPrintf("Program Path: %s", program_path.c_str());
- 
-   EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
-@@ -295,7 +295,7 @@ void QtHost::SetDataDirectory()
-   const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
-   if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
-   {
--    EmuFolders::DataRoot = Path::Combine(xdg_config_home, "duckstation");
-+    EmuFolders::DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "duckstation"));
-   }
-   else
-   {
-@@ -308,14 +308,14 @@ void QtHost::SetDataDirectory()
-       const std::string share_dir(Path::Combine(local_dir, "share"));
-       FileSystem::EnsureDirectoryExists(local_dir.c_str(), false);
-       FileSystem::EnsureDirectoryExists(share_dir.c_str(), false);
--      EmuFolders::DataRoot = Path::Combine(share_dir, "duckstation");
-+      EmuFolders::DataRoot = Path::RealPath(Path::Combine(share_dir, "duckstation"));
-     }
-   }
- #elif defined(__APPLE__)
-   static constexpr char MAC_DATA_DIR[] = "Library/Application Support/DuckStation";
-   const char* home_dir = getenv("HOME");
-   if (home_dir)
--    EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR);
-+    EmuFolders::DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
- #endif
- 
-   // make sure it exists
diff --git a/emulators/duckstation/files/patch-5246252.txt b/emulators/duckstation/files/patch-5246252.txt
deleted file mode 100644
index 35487f7939fa..000000000000
--- a/emulators/duckstation/files/patch-5246252.txt
+++ /dev/null
@@ -1,369 +0,0 @@
-Backport 5246252 from upstream
-
-commit 524625269fe5f365a10dbfc2e18c325b6c4fab61
-Author: Stenzek <stenzek@gmail.com>
-Date:   Tue Dec 5 15:21:37 2023 +1000
-
-    Path: Add RealPath()
-
-diff --git a/src/common-tests/path_tests.cpp b/src/common-tests/path_tests.cpp
-index c0e58526..03b307e4 100644
---- src/common-tests/path_tests.cpp
-+++ src/common-tests/path_tests.cpp
-@@ -5,7 +5,7 @@
- #include "common/types.h"
- #include <gtest/gtest.h>
- 
--TEST(FileSystem, ToNativePath)
-+TEST(Path, ToNativePath)
- {
-   ASSERT_EQ(Path::ToNativePath(""), "");
- 
-@@ -29,7 +29,7 @@ TEST(FileSystem, ToNativePath)
- #endif
- }
- 
--TEST(FileSystem, IsAbsolute)
-+TEST(Path, IsAbsolute)
- {
-   ASSERT_FALSE(Path::IsAbsolute(""));
-   ASSERT_FALSE(Path::IsAbsolute("foo"));
-@@ -61,7 +61,7 @@ TEST(FileSystem, IsAbsolute)
- #endif
- }
- 
--TEST(FileSystem, Canonicalize)
-+TEST(Path, Canonicalize)
- {
-   ASSERT_EQ(Path::Canonicalize(""), Path::ToNativePath(""));
-   ASSERT_EQ(Path::Canonicalize("foo/bar/../baz"), Path::ToNativePath("foo/baz"));
-@@ -72,10 +72,8 @@ TEST(FileSystem, Canonicalize)
-   ASSERT_EQ(Path::Canonicalize("./foo"), Path::ToNativePath("foo"));
-   ASSERT_EQ(Path::Canonicalize("../foo"), Path::ToNativePath("../foo"));
-   ASSERT_EQ(Path::Canonicalize("foo/b🙃ar/../b🙃az/./foo"), Path::ToNativePath("foo/b🙃az/foo"));
--  ASSERT_EQ(
--    Path::Canonicalize(
--      "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az/../foℹ︎o"),
--    Path::ToNativePath("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/foℹ︎o"));
-+  ASSERT_EQ(Path::Canonicalize("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az/../foℹ︎o"),
-+            Path::ToNativePath("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/foℹ︎o"));
- #ifdef _WIN32
-   ASSERT_EQ(Path::Canonicalize("C:\\foo\\bar\\..\\baz\\.\\foo"), "C:\\foo\\baz\\foo");
-   ASSERT_EQ(Path::Canonicalize("C:/foo\\bar\\..\\baz\\.\\foo"), "C:\\foo\\baz\\foo");
-@@ -87,7 +85,7 @@ TEST(FileSystem, Canonicalize)
- #endif
- }
- 
--TEST(FileSystem, Combine)
-+TEST(Path, Combine)
- {
-   ASSERT_EQ(Path::Combine("", ""), Path::ToNativePath(""));
-   ASSERT_EQ(Path::Combine("foo", "bar"), Path::ToNativePath("foo/bar"));
-@@ -108,7 +106,7 @@ TEST(FileSystem, Combine)
- #endif
- }
- 
--TEST(FileSystem, AppendDirectory)
-+TEST(Path, AppendDirectory)
- {
-   ASSERT_EQ(Path::AppendDirectory("foo/bar", "baz"), Path::ToNativePath("foo/baz/bar"));
-   ASSERT_EQ(Path::AppendDirectory("", "baz"), Path::ToNativePath("baz"));
-@@ -122,7 +120,7 @@ TEST(FileSystem, AppendDirectory)
- #endif
- }
- 
--TEST(FileSystem, MakeRelative)
-+TEST(Path, MakeRelative)
- {
-   ASSERT_EQ(Path::MakeRelative("", ""), Path::ToNativePath(""));
-   ASSERT_EQ(Path::MakeRelative("foo", ""), Path::ToNativePath("foo"));
-@@ -141,8 +139,7 @@ TEST(FileSystem, MakeRelative)
-   ASSERT_EQ(Path::MakeRelative(A "foo/b🙃ar", A "foo/b🙃az"), Path::ToNativePath("../b🙃ar"));
-   ASSERT_EQ(Path::MakeRelative(A "f🙃oo/b🙃ar", A "f🙃oo/b🙃az"), Path::ToNativePath("../b🙃ar"));
-   ASSERT_EQ(
--    Path::MakeRelative(A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃ar",
--                       A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az"),
-+    Path::MakeRelative(A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃ar", A "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱/b🙃az"),
-     Path::ToNativePath("../b🙃ar"));
- 
- #undef A
-@@ -154,7 +151,7 @@ TEST(FileSystem, MakeRelative)
- #endif
- }
- 
--TEST(FileSystem, GetExtension)
-+TEST(Path, GetExtension)
- {
-   ASSERT_EQ(Path::GetExtension("foo"), "");
-   ASSERT_EQ(Path::GetExtension("foo.txt"), "txt");
-@@ -164,7 +161,7 @@ TEST(FileSystem, GetExtension)
-   ASSERT_EQ(Path::GetExtension("a/b/foo"), "");
- }
- 
--TEST(FileSystem, GetFileName)
-+TEST(Path, GetFileName)
- {
-   ASSERT_EQ(Path::GetFileName(""), "");
-   ASSERT_EQ(Path::GetFileName("foo"), "foo");
-@@ -179,7 +176,7 @@ TEST(FileSystem, GetFileName)
- #endif
- }
- 
--TEST(FileSystem, GetFileTitle)
-+TEST(Path, GetFileTitle)
- {
-   ASSERT_EQ(Path::GetFileTitle(""), "");
-   ASSERT_EQ(Path::GetFileTitle("foo"), "foo");
-@@ -193,7 +190,7 @@ TEST(FileSystem, GetFileTitle)
- #endif
- }
- 
--TEST(FileSystem, GetDirectory)
-+TEST(Path, GetDirectory)
- {
-   ASSERT_EQ(Path::GetDirectory(""), "");
-   ASSERT_EQ(Path::GetDirectory("foo"), "");
-@@ -207,7 +204,7 @@ TEST(FileSystem, GetDirectory)
- #endif
- }
- 
--TEST(FileSystem, ChangeFileName)
-+TEST(Path, ChangeFileName)
- {
-   ASSERT_EQ(Path::ChangeFileName("", ""), Path::ToNativePath(""));
-   ASSERT_EQ(Path::ChangeFileName("", "bar"), Path::ToNativePath("bar"));
-@@ -227,13 +224,14 @@ TEST(FileSystem, ChangeFileName)
- #endif
- }
- 
--TEST(FileSystem, SanitizeFileName)
-+TEST(Path, SanitizeFileName)
- {
-   ASSERT_EQ(Path::SanitizeFileName("foo"), "foo");
-   ASSERT_EQ(Path::SanitizeFileName("foo/bar"), "foo_bar");
-   ASSERT_EQ(Path::SanitizeFileName("f🙃o"), "f🙃o");
-   ASSERT_EQ(Path::SanitizeFileName("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"), "ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
--  ASSERT_EQ(Path::SanitizeFileName("abcdefghijlkmnopqrstuvwxyz-0123456789+&=_[]{}"), "abcdefghijlkmnopqrstuvwxyz-0123456789+&=_[]{}");
-+  ASSERT_EQ(Path::SanitizeFileName("abcdefghijlkmnopqrstuvwxyz-0123456789+&=_[]{}"),
-+            "abcdefghijlkmnopqrstuvwxyz-0123456789+&=_[]{}");
-   ASSERT_EQ(Path::SanitizeFileName("some*path**with*asterisks"), "some_path__with_asterisks");
- #ifdef _WIN32
-   ASSERT_EQ(Path::SanitizeFileName("foo:"), "foo_");
-@@ -243,4 +241,18 @@ TEST(FileSystem, SanitizeFileName)
-   ASSERT_EQ(Path::SanitizeFileName("foo\\bar", false), "foo\\bar");
- #endif
-   ASSERT_EQ(Path::SanitizeFileName("foo/bar", false), "foo/bar");
--}
-\ No newline at end of file
-+}
-+
-+#if 0
-+
-+// Relies on presence of files.
-+TEST(Path, RealPath)
-+{
-+#ifdef _WIN32
-+  ASSERT_EQ(Path::RealPath("C:\\Users\\Me\\Desktop\\foo\\baz"), "C:\\Users\\Me\\Desktop\\foo\\bar\\baz");
-+#else
-+  ASSERT_EQ(Path::RealPath("/lib/foo/bar"), "/usr/lib/foo/bar");
-+#endif
-+}
-+
-+#endif
-\ No newline at end of file
-diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp
-index 4a5fc6b0..4ce4b9ed 100644
---- src/common/file_system.cpp
-+++ src/common/file_system.cpp
-@@ -12,6 +12,7 @@
- #include <cstdlib>
- #include <cstring>
- #include <limits>
-+#include <numeric>
- 
- #ifdef __APPLE__
- #include <mach-o/dyld.h>
-@@ -192,6 +193,161 @@ bool Path::IsAbsolute(const std::string_view& path)
- #endif
- }
- 
-+std::string Path::RealPath(const std::string_view& path)
-+{
-+  // Resolve non-absolute paths first.
-+  std::vector<std::string_view> components;
-+  if (!IsAbsolute(path))
-+    components = Path::SplitNativePath(Path::Combine(FileSystem::GetWorkingDirectory(), path));
-+  else
-+    components = Path::SplitNativePath(path);
-+
-+  std::string realpath;
-+  if (components.empty())
-+    return realpath;
-+
-+  // Different to path because relative.
-+  realpath.reserve(std::accumulate(components.begin(), components.end(), static_cast<size_t>(0),
-+                                   [](size_t l, const std::string_view& s) { return l + s.length(); }) +
-+                   components.size() + 1);
-+
-+#ifdef _WIN32
-+  std::wstring wrealpath;
-+  std::vector<WCHAR> symlink_buf;
-+  wrealpath.reserve(realpath.size());
-+  symlink_buf.resize(path.size() + 1);
-+
-+  // Check for any symbolic links throughout the path while adding components.
-+  bool test_symlink = true;
-+  for (const std::string_view& comp : components)
-+  {
-+    if (!realpath.empty())
-+      realpath.push_back(FS_OSPATH_SEPARATOR_CHARACTER);
-+    realpath.append(comp);
-+    if (test_symlink)
-+    {
-+      DWORD attribs;
-+      if (StringUtil::UTF8StringToWideString(wrealpath, realpath) &&
-+          (attribs = GetFileAttributesW(wrealpath.c_str())) != INVALID_FILE_ATTRIBUTES)
-+      {
-+        // if not a link, go to the next component
-+        if (attribs & FILE_ATTRIBUTE_REPARSE_POINT)
-+        {
-+          const HANDLE hFile =
-+            CreateFileW(wrealpath.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-+                        nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
-+          if (hFile != INVALID_HANDLE_VALUE)
-+          {
-+            // is a link! resolve it.
-+            DWORD ret = GetFinalPathNameByHandleW(hFile, symlink_buf.data(), static_cast<DWORD>(symlink_buf.size()),
-+                                                  FILE_NAME_NORMALIZED);
-+            if (ret > symlink_buf.size())
-+            {
-+              symlink_buf.resize(ret);
-+              ret = GetFinalPathNameByHandleW(hFile, symlink_buf.data(), static_cast<DWORD>(symlink_buf.size()),
-+                                              FILE_NAME_NORMALIZED);
-+            }
-+            if (ret != 0)
-+              StringUtil::WideStringToUTF8String(realpath, std::wstring_view(symlink_buf.data(), ret));
-+            else
-+              test_symlink = false;
-+
-+            CloseHandle(hFile);
-+          }
-+        }
-+      }
-+      else
-+      {
-+        // not a file or link
-+        test_symlink = false;
-+      }
-+    }
-+  }
-+
-+  // GetFinalPathNameByHandleW() adds a \\?\ prefix, so remove it.
-+  if (realpath.starts_with("\\\\?\\") && IsAbsolute(std::string_view(realpath.data() + 4, realpath.size() - 4)))
-+    realpath.erase(0, 4);
-+
-+#else
-+  // Why this monstrosity instead of calling realpath()? realpath() only works on files that exist.
-+  std::string basepath;
-+  std::string symlink;
-+
-+  basepath.reserve(realpath.capacity());
-+  symlink.resize(realpath.capacity());
-+
-+  // Check for any symbolic links throughout the path while adding components.
-+  bool test_symlink = true;
-+  for (const std::string_view& comp : components)
-+  {
-+    if (!test_symlink)
-+    {
-+      realpath.push_back(FS_OSPATH_SEPARATOR_CHARACTER);
-+      realpath.append(comp);
-+      continue;
-+    }
-+
-+    basepath = realpath;
-+    if (realpath.empty() || realpath.back() != FS_OSPATH_SEPARATOR_CHARACTER)
-+      realpath.push_back(FS_OSPATH_SEPARATOR_CHARACTER);
-+    realpath.append(comp);
-+
-+    // Check if the last component added is a symlink
-+    struct stat sb;
-+    if (lstat(realpath.c_str(), &sb) != 0)
-+    {
-+      // Don't bother checking any further components once we error out.
-+      test_symlink = false;
-+      continue;
-+    }
-+    else if (!S_ISLNK(sb.st_mode))
-+    {
-+      // Nope, keep going.
-+      continue;
-+    }
-+
-+    for (;;)
-+    {
-+      ssize_t sz = readlink(realpath.c_str(), symlink.data(), symlink.size());
-+      if (sz < 0)
-+      {
-+        // shouldn't happen, due to the S_ISLNK check above.
-+        test_symlink = false;
-+        break;
-+      }
-+      else if (static_cast<size_t>(sz) == symlink.size())
-+      {
-+        // need a larger buffer
-+        symlink.resize(symlink.size() * 2);
-+        continue;
-+      }
-+      else
-+      {
-+        // is a link, and we resolved it. gotta check if the symlink itself is relative :(
-+        symlink.resize(static_cast<size_t>(sz));
-+        if (!Path::IsAbsolute(symlink))
-+        {
-+          // symlink is relative to the directory of the symlink
-+          realpath = basepath;
-+          if (realpath.empty() || realpath.back() != FS_OSPATH_SEPARATOR_CHARACTER)
-+            realpath.push_back(FS_OSPATH_SEPARATOR_CHARACTER);
-+          realpath.append(symlink);
-+        }
-+        else
-+        {
-+          // Use the new, symlinked path.
-+          realpath = symlink;
-+        }
-+
-+        break;
-+      }
-+    }
-+  }
-+#endif
-+
-+  return realpath;
-+}
-+
- std::string Path::ToNativePath(const std::string_view& path)
- {
-   std::string ret;
-@@ -1382,6 +1538,7 @@ std::string FileSystem::GetProgramPath()
-     break;
-   }
- 
-+  // Windows symlinks don't behave silly like Linux, so no need to RealPath() it.
-   return StringUtil::WideStringToUTF8String(buffer);
- }
- 
-diff --git a/src/common/path.h b/src/common/path.h
-index 7c03c1ad..12d86471 100644
---- src/common/path.h
-+++ src/common/path.h
-@@ -31,6 +31,9 @@ void SanitizeFileName(std::string* str, bool strip_slashes = true);
- /// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix).
- bool IsAbsolute(const std::string_view& path);
- 
-+/// Resolves any symbolic links in the specified path.
-+std::string RealPath(const std::string_view& path);
-+
- /// Makes the specified path relative to another (e.g. /a/b/c, /a/b -> ../c).
- /// Both paths must be relative, otherwise this function will just return the input path.
- std::string MakeRelative(const std::string_view& path, const std::string_view& relative_to);
diff --git a/emulators/duckstation/files/patch-5486a7a.txt b/emulators/duckstation/files/patch-5486a7a.txt
deleted file mode 100644
index f49e3f6f6af7..000000000000
--- a/emulators/duckstation/files/patch-5486a7a.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Backport 5486a7a from upstream
-
-commit 5486a7a467dc0cd502bd8c4e7eb7a3c95a5a3c02
-Author: Ganael Laplanche <ganael.laplanche@martymac.org>
-Date:   Wed Nov 29 21:05:21 2023 +0100
-
-    Fix get_thread_time() declaration on FreeBSD
-
-diff --git a/src/common/threading.cpp b/src/common/threading.cpp
-index ac272ff1..8dacce83 100644
---- src/common/threading.cpp
-+++ src/common/threading.cpp
-@@ -64,7 +64,7 @@ static u64 getthreadtime(thread_port_t thread)
- }
- #endif
- 
--#ifdef __linux__
-+#if defined(__linux__) || defined(__FreeBSD__)
- // Helper function to get either either the current cpu usage
- // in called thread or in id thread
- static u64 get_thread_time(void* id = 0)
-@@ -227,7 +227,7 @@ u64 Threading::ThreadHandle::GetCPUTime() const
-   return user.u64time + kernel.u64time;
- #elif defined(__APPLE__)
-   return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle));
--#elif defined(__linux__)
-+#elif defined(__linux__) || defined(__FreeBSD__)
-   return get_thread_time(m_native_handle);
- #else
-   return 0;
diff --git a/emulators/duckstation/files/patch-af046c8.txt b/emulators/duckstation/files/patch-af046c8.txt
deleted file mode 100644
index 1830dd4933d5..000000000000
--- a/emulators/duckstation/files/patch-af046c8.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-Backport af046c8 from upstream
-
-commit af046c8987ec3c580eff8a0c7c438762377fdbca
-Author: Ganael Laplanche <ganael.laplanche@martymac.org>
-Date:   Wed Nov 29 20:54:12 2023 +0100
-
-    Fix build on FreeBSD
-    
-    FreeBSD's alloca(3) only needs <stdlib.h>
-
-diff --git a/src/common/byte_stream.cpp b/src/common/byte_stream.cpp
-index bb26af0f..18609996 100644
---- src/common/byte_stream.cpp
-+++ src/common/byte_stream.cpp
-@@ -28,8 +28,10 @@
- #ifdef _MSC_VER
- #include <malloc.h>
- #else
-+#if !defined(__FreeBSD__)
- #include <alloca.h>
- #endif
-+#endif
- 
- Log_SetChannel(ByteStream);
- 
diff --git a/emulators/duckstation/files/patch-b6d6756.txt b/emulators/duckstation/files/patch-b6d6756.txt
deleted file mode 100644
index aa3be9286ef5..000000000000
--- a/emulators/duckstation/files/patch-b6d6756.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-Backport b6d6756 from upstream
-
-commit b6d67560e39ca3c7154d97355fec988210a460e5
-Author: Ganael Laplanche <ganael.laplanche@martymac.org>
-Date:   Wed Nov 29 20:38:56 2023 +0100
-
-    Fix data directory handling on FreeBSD
-
-diff --git a/src/duckstation-nogui/nogui_host.cpp b/src/duckstation-nogui/nogui_host.cpp
-index 5543c2c9..8e2778ed 100644
---- src/duckstation-nogui/nogui_host.cpp
-+++ src/duckstation-nogui/nogui_host.cpp
-@@ -185,7 +185,7 @@ void NoGUIHost::SetDataDirectory()
-       EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "DuckStation");
-     CoTaskMemFree(documents_directory);
-   }
--#elif defined(__linux__)
-+#elif defined(__linux__) || defined(__FreeBSD__)
-   // Use $XDG_CONFIG_HOME/duckstation if it exists.
-   const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
-   if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
-diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp
-index a2039160..b7977cb6 100644
---- src/duckstation-qt/qthost.cpp
-+++ src/duckstation-qt/qthost.cpp
-@@ -290,7 +290,7 @@ void QtHost::SetDataDirectory()
-       EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "DuckStation");
-     CoTaskMemFree(documents_directory);
-   }
--#elif defined(__linux__)
-+#elif defined(__linux__) || defined(__FreeBSD__)
-   // Use $XDG_CONFIG_HOME/duckstation if it exists.
-   const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
-   if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
diff --git a/emulators/duckstation/pkg-plist b/emulators/duckstation/pkg-plist
index fa196af62f5a..bcffa05803d8 100644
--- a/emulators/duckstation/pkg-plist
+++ b/emulators/duckstation/pkg-plist
@@ -6,6 +6,7 @@ share/pixmaps/duckstation.png
 %%DATADIR%%/resources/fonts/Roboto-Regular.ttf
 %%DATADIR%%/resources/fonts/RobotoMono-Medium.ttf
 %%DATADIR%%/resources/fonts/fa-solid-900.ttf
+%%DATADIR%%/resources/fonts/promptfont.otf
 %%DATADIR%%/resources/fullscreenui/NTSC-J.png
 %%DATADIR%%/resources/fullscreenui/NTSC-U.png
 %%DATADIR%%/resources/fullscreenui/PAL.png