git: b8b789478ef4 - main - emulators/libretro-pcsx2: New port: Standalone port of pcsx2 to libretro emulator

From: Neel Chauhan <nc_at_FreeBSD.org>
Date: Thu, 19 May 2022 17:49:26 UTC
The branch main has been updated by nc:

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

commit b8b789478ef4616e10614abc1ed1488425aa8336
Author:     Timothy Beyer <beyert_freebsd@fastmail.net>
AuthorDate: 2022-05-17 03:53:46 +0000
Commit:     Neel Chauhan <nc@FreeBSD.org>
CommitDate: 2022-05-19 17:49:22 +0000

    emulators/libretro-pcsx2: New port: Standalone port of pcsx2 to libretro emulator
    
    PR:     252191
---
 emulators/Makefile                                 |   1 +
 emulators/libretro-pcsx2/Makefile                  |  65 +++
 emulators/libretro-pcsx2/distinfo                  |   3 +
 ...rty_wxwidgets3.0_src_unix_fswatcher__kqueue.cpp | 459 +++++++++++++++++++++
 .../patch-3rdparty_wxwidgets3.0_CMakeLists.txt     |  14 +
 .../patch-3rdparty_wxwidgets3.0_UsewxWidgets.cmake |  11 +
 ...-3rdparty_wxwidgets3.0_include_nogui_wx_setup.h |  11 +
 .../libretro-pcsx2/files/patch-CMakeLists.txt      |  14 +
 .../files/patch-common_include_Utilities_General.h |  11 +
 .../libretro-pcsx2/files/patch-pcsx2_SPU2_spu2.cpp |  14 +
 emulators/libretro-pcsx2/pkg-descr                 |   9 +
 11 files changed, 612 insertions(+)

diff --git a/emulators/Makefile b/emulators/Makefile
index 574973a982a1..20c3c7fbd15c 100644
--- a/emulators/Makefile
+++ b/emulators/Makefile
@@ -59,6 +59,7 @@
     SUBDIR += libdsk
     SUBDIR += libretro-flycast
     SUBDIR += libretro-mame
+    SUBDIR += libretro-pcsx2
     SUBDIR += libretro-ppsspp
     SUBDIR += libretro-reicast
     SUBDIR += libretro-vice
diff --git a/emulators/libretro-pcsx2/Makefile b/emulators/libretro-pcsx2/Makefile
new file mode 100644
index 000000000000..779c89f7d839
--- /dev/null
+++ b/emulators/libretro-pcsx2/Makefile
@@ -0,0 +1,65 @@
+# $FreeBSD$
+
+PORTNAME=	libretro-pcsx2
+PORTVERSION=	0.20201030
+CATEGORIES=	emulators games
+
+MAINTAINER=	beyert@cs.ucr.edu
+COMMENT=	Standalone port of pcsx2 to libretro
+
+LICENSE=	GPLv3
+LICENSE_FILE=	${WRKSRC}/COPYING.GPLv3
+
+ONLY_FOR_ARCHS=	>i386 amd64
+
+LIB_DEPENDS=	libcdio.so:sysutils/libcdio \
+		libharfbuzz.so:print/harfbuzz \
+		libpng16.so:graphics/png \
+		libportaudio.so:audio/portaudio \
+		libSoundTouch.so:audio/soundtouch
+
+USES=		cmake compiler:c++11-lib
+
+CPPFLAGS+=		-I${LOCALBASE}/include/wx-3.0
+USE_CXXSTD=		c++11
+#LDFLAGS+=	-L${LOCALBASE}/lib -I/usr/lib
+USE_LDCONFIG=		yes
+CMAKE_CPP_FLAGS=	${CPPFLAGS}
+CMAKE_PREFIX_PATH=	${LOCALBASE}/include/wx-3.0
+CMAKE_C_FLAGS=		${CFLAGS}
+CMAKE_CXX_FLAGS=	${CFLAGS}
+CMAKE_ARGS+=		-DLIBRETRO=yes
+CMAKE_ARGS+=		-Dgtk_INCLUDE_DIR="${LOCALBASE}/include/gtk-3.0" \
+			-DwxWidgets_INCLUDE_DIRS="${LOCALBASE}/include/wx-3.0"
+
+# lib depends on devel/ccache
+WITH_CCACHE_BUILD=	yes
+
+HAVE_GTK3=	true
+#USES=		gnome xorg gl sdl dos2unix cmake:insource iconv gettext linux:c7 pkgconfig
+#USE_LINUX=	libaio
+USE_WX=		3.0+
+#USE_XORG=	ice x11 xv xext xxf86vm xtst xrandr xi
+USE_GL=		gl glew glu
+USE_GNOME=	glib20
+#USE_SDL=	sdl2
+
+MAKE_JOBS_UNSAFE=	yes
+
+USE_GITHUB=	yes
+GH_ACCOUNT=	libretro
+GH_PROJECT=	pcsx2
+GH_TAGNAME=	1251fa4
+
+PLIST_FILES=	lib/libretro/pcsx2_libretro.so
+
+post-patch:
+	${CP} files/3rdparty_wxwidgets3.0_src_unix_fswatcher__kqueue.cpp \
+		${WRKSRC}/3rdparty/wxwidgets3.0/src/unix/fswatcher_kqueue.cpp
+
+do-install:
+	${MKDIR} ${STAGEDIR}/${PREFIX}/lib/libretro;
+	${INSTALL_LIB} ${WRKDIR}/.build/pcsx2/pcsx2_libretro.so \
+		${STAGEDIR}/${PREFIX}/lib/libretro;
+
+.include <bsd.port.mk>
diff --git a/emulators/libretro-pcsx2/distinfo b/emulators/libretro-pcsx2/distinfo
new file mode 100644
index 000000000000..36d8005daf71
--- /dev/null
+++ b/emulators/libretro-pcsx2/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1604098409
+SHA256 (libretro-pcsx2-0.20201030-1251fa4_GH0.tar.gz) = 01b329b4bba210022f0f0f889b2e4722ef530b766eaf7036194a53668b47a245
+SIZE (libretro-pcsx2-0.20201030-1251fa4_GH0.tar.gz) = 15636747
diff --git a/emulators/libretro-pcsx2/files/3rdparty_wxwidgets3.0_src_unix_fswatcher__kqueue.cpp b/emulators/libretro-pcsx2/files/3rdparty_wxwidgets3.0_src_unix_fswatcher__kqueue.cpp
new file mode 100644
index 000000000000..55cb787cd1ae
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/3rdparty_wxwidgets3.0_src_unix_fswatcher__kqueue.cpp
@@ -0,0 +1,459 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        src/unix/fswatcher_kqueue.cpp
+// Purpose:     kqueue-based wxFileSystemWatcher implementation
+// Author:      Bartosz Bekier
+// Created:     2009-05-26
+// Copyright:   (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_FSWATCHER
+
+#include "wx/fswatcher.h"
+
+#ifdef wxHAS_KQUEUE
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/param.h>
+
+#include "wx/dynarray.h"
+#include "wx/evtloop.h"
+#include "wx/evtloopsrc.h"
+
+#include "wx/private/fswatcher.h"
+
+namespace
+{
+
+// NetBSD is different as it uses intptr_t as type of kevent struct udata field
+// for some reason, instead of "void*" as all the other platforms using kqueue.
+#ifdef __NetBSD__
+    inline intptr_t ToUdata(void* d) { return reinterpret_cast<intptr_t>(d); }
+    inline void* FromUdata(intptr_t d) { return reinterpret_cast<void*>(d); }
+#else
+    inline void* ToUdata(void* d) { return d; }
+    inline void* FromUdata(void* d) { return d; }
+#endif
+
+} // anonymous namespace
+
+// ============================================================================
+// wxFSWSourceHandler helper class
+// ============================================================================
+
+class wxFSWatcherImplKqueue;
+
+/**
+ * Handler for handling i/o from inotify descriptor
+ */
+class wxFSWSourceHandler : public wxEventLoopSourceHandler
+{
+public:
+    wxFSWSourceHandler(wxFSWatcherImplKqueue* service) :
+        m_service(service)
+    {  }
+
+    virtual void OnReadWaiting();
+    virtual void OnWriteWaiting();
+    virtual void OnExceptionWaiting();
+
+protected:
+    wxFSWatcherImplKqueue* m_service;
+};
+
+// ============================================================================
+// wxFSWatcherImpl implementation & helper wxFSWSourceHandler implementation
+// ============================================================================
+
+/**
+ * Helper class encapsulating inotify mechanism
+ */
+class wxFSWatcherImplKqueue : public wxFSWatcherImpl
+{
+public:
+    wxFSWatcherImplKqueue(wxFileSystemWatcherBase* watcher) :
+        wxFSWatcherImpl(watcher),
+        m_source(NULL),
+        m_kfd(-1)
+    {
+        m_handler = new wxFSWSourceHandler(this);
+    }
+
+    virtual ~wxFSWatcherImplKqueue()
+    {
+        // we close kqueue only if initialized before
+        if (IsOk())
+        {
+            Close();
+        }
+
+        delete m_handler;
+    }
+
+    bool Init()
+    {
+        wxCHECK_MSG( !IsOk(), false,
+                     "Kqueue appears to be already initialized" );
+
+        wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+        wxCHECK_MSG( loop, false, "File system watcher needs an active loop" );
+
+        // create kqueue
+        m_kfd = kqueue();
+        if (m_kfd == -1)
+        {
+            wxLogSysError(_("Unable to create kqueue instance"));
+            return false;
+        }
+
+        // create source
+        m_source = loop->AddSourceForFD(m_kfd, m_handler, wxEVENT_SOURCE_INPUT);
+
+        return m_source != NULL;
+    }
+
+    void Close()
+    {
+        wxCHECK_RET( IsOk(),
+                    "Kqueue not initialized or invalid kqueue descriptor" );
+
+        if ( close(m_kfd) != 0 )
+        {
+            wxLogSysError(_("Error closing kqueue instance"));
+        }
+
+        wxDELETE(m_source);
+    }
+
+    virtual bool DoAdd(wxSharedPtr<wxFSWatchEntryKq> watch)
+    {
+        wxCHECK_MSG( IsOk(), false,
+                    "Kqueue not initialized or invalid kqueue descriptor" );
+
+        struct kevent event;
+        int action = EV_ADD | EV_ENABLE | EV_CLEAR | EV_ERROR;
+        int flags = Watcher2NativeFlags(watch->GetFlags());
+        EV_SET( &event, watch->GetFileDescriptor(), EVFILT_VNODE, action,
+                flags, 0, ToUdata(watch.get()) );
+
+        // TODO more error conditions according to man
+        // TODO best deal with the error here
+        int ret = kevent(m_kfd, &event, 1, NULL, 0, NULL);
+        if (ret == -1)
+        {
+            wxLogSysError(_("Unable to add kqueue watch"));
+            return false;
+        }
+
+        return true;
+    }
+
+    virtual bool DoRemove(wxSharedPtr<wxFSWatchEntryKq> watch)
+    {
+        wxCHECK_MSG( IsOk(), false,
+                    "Kqueue not initialized or invalid kqueue descriptor" );
+
+        // TODO more error conditions according to man
+        // XXX closing file descriptor removes the watch. The logic resides in
+        // the watch which is not nice, but effective and simple
+        if ( !watch->Close() )
+        {
+            wxLogSysError(_("Unable to remove kqueue watch"));
+            return false;
+        }
+
+        return true;
+    }
+
+    virtual bool RemoveAll()
+    {
+        wxFSWatchEntries::iterator it = m_watches.begin();
+        for ( ; it != m_watches.end(); ++it )
+        {
+            (void) DoRemove(it->second);
+        }
+        m_watches.clear();
+        return true;
+    }
+
+    // return true if there was no error, false on error
+    bool ReadEvents()
+    {
+        wxCHECK_MSG( IsOk(), false,
+                    "Kqueue not initialized or invalid kqueue descriptor" );
+
+        // read events
+        do
+        {
+            struct kevent event;
+            struct timespec timeout = {0, 0};
+            int ret = kevent(m_kfd, NULL, 0, &event, 1, &timeout);
+            if (ret == -1)
+            {
+                wxLogSysError(_("Unable to get events from kqueue"));
+                return false;
+            }
+            else if (ret == 0)
+            {
+                return true;
+            }
+
+            // we have event, so process it
+            ProcessNativeEvent(event);
+        }
+        while (true);
+
+        // when ret>0 we still have events, when ret<=0 we return
+        wxFAIL_MSG( "Never reached" );
+        return true;
+    }
+
+    bool IsOk() const
+    {
+        return m_source != NULL;
+    }
+
+protected:
+    // returns all new dirs/files present in the immediate level of the dir
+    // pointed by watch.GetPath(). "new" means created between the last time
+    // the state of watch was computed and now
+    void FindChanges(wxFSWatchEntryKq& watch,
+                     wxArrayString& changedFiles,
+                     wxArrayInt& changedFlags)
+    {
+        wxFSWatchEntryKq::wxDirState old = watch.GetLastState();
+        watch.RefreshState();
+        wxFSWatchEntryKq::wxDirState curr = watch.GetLastState();
+
+        // iterate over old/curr file lists and compute changes
+        wxArrayString::iterator oit = old.files.begin();
+        wxArrayString::iterator cit = curr.files.begin();
+        for ( ; oit != old.files.end() && cit != curr.files.end(); )
+        {
+            if ( *cit == *oit )
+            {
+                ++cit;
+                ++oit;
+            }
+            else if ( *cit <= *oit )
+            {
+                changedFiles.push_back(*cit);
+                changedFlags.push_back(wxFSW_EVENT_CREATE);
+                ++cit;
+            }
+            else // ( *cit > *oit )
+            {
+                changedFiles.push_back(*oit);
+                changedFlags.push_back(wxFSW_EVENT_DELETE);
+                ++oit;
+            }
+        }
+
+        // border conditions
+        if ( oit == old.files.end() )
+        {
+            for ( ; cit != curr.files.end(); ++cit )
+            {
+                changedFiles.push_back( *cit );
+                changedFlags.push_back(wxFSW_EVENT_CREATE);
+            }
+        }
+        else if ( cit == curr.files.end() )
+        {
+            for ( ; oit != old.files.end(); ++oit )
+            {
+                changedFiles.push_back( *oit );
+                changedFlags.push_back(wxFSW_EVENT_DELETE);
+            }
+        }
+
+        wxASSERT( changedFiles.size() == changedFlags.size() );
+
+#if 0
+        wxLogTrace(wxTRACE_FSWATCHER, "Changed files:");
+        wxArrayString::iterator it = changedFiles.begin();
+        wxArrayInt::iterator it2 = changedFlags.begin();
+        for ( ; it != changedFiles.end(); ++it, ++it2)
+        {
+            wxString action = (*it2 == wxFSW_EVENT_CREATE) ?
+                                "created" : "deleted";
+            wxLogTrace(wxTRACE_FSWATCHER, wxString::Format("File: '%s' %s",
+                        *it, action));
+        }
+#endif
+    }
+
+    void ProcessNativeEvent(const struct kevent& e)
+    {
+        void* const udata = FromUdata(e.udata);
+
+        wxASSERT_MSG(udata, "Null user data associated with kevent!");
+        wxLogTrace(wxTRACE_FSWATCHER, "Event: ident=%" PRIuPTR ", filter=%hd, flags=%hu, "
+#if __FreeBSD_version >= 1200033
+                   "fflags=%u, data=%" PRId64 ", user_data=%p",
+#else
+                   "fflags=%u, data=%" PRIdPTR ", user_data=%p",
+#endif
+                   e.ident, e.filter, e.flags, e.fflags, e.data, udata);
+
+        // for ease of use
+        wxFSWatchEntryKq& w = *(static_cast<wxFSWatchEntry*>(udata));
+        int nflags = e.fflags;
+
+        // clear ignored flags
+        nflags &= ~NOTE_REVOKE;
+
+        // TODO ignore events we didn't ask for + refactor this cascade ifs
+        // check for events
+        while ( nflags )
+        {
+            // when monitoring dir, this means create/delete
+            const wxString basepath = w.GetPath();
+            if ( nflags & NOTE_WRITE && wxDirExists(basepath) )
+            {
+                // NOTE_LINK is set when the dir was created, but we
+                // don't care - we look for new names in directory
+                // regardless of type. Also, clear all this, because
+                // it cannot mean more by itself
+                nflags &= ~(NOTE_WRITE | NOTE_ATTRIB | NOTE_LINK);
+
+                wxArrayString changedFiles;
+                wxArrayInt changedFlags;
+                FindChanges(w, changedFiles, changedFlags);
+
+                wxArrayString::iterator it = changedFiles.begin();
+                wxArrayInt::iterator changeType = changedFlags.begin();
+                for ( ; it != changedFiles.end(); ++it, ++changeType )
+                {
+                    const wxString fullpath = w.GetPath() +
+                                                wxFileName::GetPathSeparator() +
+                                                  *it;
+                    const wxFileName path(wxDirExists(fullpath)
+                                            ? wxFileName::DirName(fullpath)
+                                            : wxFileName::FileName(fullpath));
+
+                    wxFileSystemWatcherEvent event(*changeType, path, path);
+                    SendEvent(event);
+                }
+            }
+            else if ( nflags & NOTE_RENAME )
+            {
+                // CHECK it'd be only possible to detect name if we had
+                // parent files listing which we could confront with now and
+                // still we couldn't be sure we have the right name...
+                nflags &= ~NOTE_RENAME;
+                wxFileSystemWatcherEvent event(wxFSW_EVENT_RENAME,
+                                        basepath, wxFileName());
+                SendEvent(event);
+            }
+            else if ( nflags & NOTE_WRITE || nflags & NOTE_EXTEND )
+            {
+                nflags &= ~(NOTE_WRITE | NOTE_EXTEND);
+                wxFileSystemWatcherEvent event(wxFSW_EVENT_MODIFY,
+                                        basepath, basepath);
+                SendEvent(event);
+            }
+            else if ( nflags & NOTE_DELETE )
+            {
+                nflags &= ~(NOTE_DELETE);
+                wxFileSystemWatcherEvent event(wxFSW_EVENT_DELETE,
+                                        basepath, basepath);
+                SendEvent(event);
+            }
+            else if ( nflags & NOTE_ATTRIB )
+            {
+                nflags &= ~(NOTE_ATTRIB);
+                wxFileSystemWatcherEvent event(wxFSW_EVENT_ACCESS,
+                                        basepath, basepath);
+                SendEvent(event);
+            }
+
+            // clear any flags that won't mean anything by themselves
+            nflags &= ~(NOTE_LINK);
+        }
+    }
+
+    void SendEvent(wxFileSystemWatcherEvent& evt)
+    {
+        m_watcher->GetOwner()->ProcessEvent(evt);
+    }
+
+    static int Watcher2NativeFlags(int WXUNUSED(flags))
+    {
+        // TODO: it would be better to only subscribe to what we need
+        return NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND |
+               NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME |
+               NOTE_REVOKE;
+    }
+
+    wxFSWSourceHandler* m_handler;        // handler for kqueue event source
+    wxEventLoopSource* m_source;          // our event loop source
+
+    // descriptor created by kqueue()
+    int m_kfd;
+};
+
+
+// once we get signaled to read, actuall event reading occurs
+void wxFSWSourceHandler::OnReadWaiting()
+{
+    wxLogTrace(wxTRACE_FSWATCHER, "--- OnReadWaiting ---");
+    m_service->ReadEvents();
+}
+
+void wxFSWSourceHandler::OnWriteWaiting()
+{
+    wxFAIL_MSG("We never write to kqueue descriptor.");
+}
+
+void wxFSWSourceHandler::OnExceptionWaiting()
+{
+    wxFAIL_MSG("We never receive exceptions on kqueue descriptor.");
+}
+
+
+// ============================================================================
+// wxKqueueFileSystemWatcher implementation
+// ============================================================================
+
+wxKqueueFileSystemWatcher::wxKqueueFileSystemWatcher()
+    : wxFileSystemWatcherBase()
+{
+    Init();
+}
+
+wxKqueueFileSystemWatcher::wxKqueueFileSystemWatcher(const wxFileName& path,
+                                                     int events)
+    : wxFileSystemWatcherBase()
+{
+    if (!Init())
+    {
+        wxDELETE(m_service);
+        return;
+    }
+
+    Add(path, events);
+}
+
+wxKqueueFileSystemWatcher::~wxKqueueFileSystemWatcher()
+{
+}
+
+bool wxKqueueFileSystemWatcher::Init()
+{
+    m_service = new wxFSWatcherImplKqueue(this);
+    return m_service->Init();
+}
+
+#endif // wxHAS_KQUEUE
+
+#endif // wxUSE_FSWATCHER
diff --git a/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_CMakeLists.txt b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_CMakeLists.txt
new file mode 100644
index 000000000000..8fa9ee4b563d
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_CMakeLists.txt
@@ -0,0 +1,14 @@
+--- 3rdparty/wxwidgets3.0/CMakeLists.txt.orig	2020-10-29 23:31:05 UTC
++++ 3rdparty/wxwidgets3.0/CMakeLists.txt
+@@ -1,10 +1,10 @@
+ if(UNIX)
+ set(wxUnixSources
++   src/unix/fswatcher_kqueue.cpp
+    src/unix/appunix.cpp
+    src/unix/dir.cpp
+    src/unix/dlunix.cpp
+    src/unix/evtloopunix.cpp
+-   src/unix/epolldispatcher.cpp
+    src/unix/fdiounix.cpp
+    src/unix/stackwalk.cpp
+    src/unix/stdpaths.cpp
diff --git a/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_UsewxWidgets.cmake b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_UsewxWidgets.cmake
new file mode 100644
index 000000000000..96b899de88ec
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_UsewxWidgets.cmake
@@ -0,0 +1,11 @@
+--- 3rdparty/wxwidgets3.0/UsewxWidgets.cmake.orig	2020-10-29 23:31:05 UTC
++++ 3rdparty/wxwidgets3.0/UsewxWidgets.cmake
+@@ -11,7 +11,7 @@ if(UNIX)
+    if(APPLE)
+       add_definitions(-D__DARWIN__)
+    else()
+-       add_definitions(-D__LINUX__)
++       add_definitions(-D__BSD__)
+    endif()
+ elseif(WIN32)
+    add_definitions(-D__WINDOWS__)
diff --git a/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_include_nogui_wx_setup.h b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_include_nogui_wx_setup.h
new file mode 100644
index 000000000000..fe0096b422c0
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-3rdparty_wxwidgets3.0_include_nogui_wx_setup.h
@@ -0,0 +1,11 @@
+--- 3rdparty/wxwidgets3.0/include/nogui/wx/setup.h.orig	2020-10-29 23:31:05 UTC
++++ 3rdparty/wxwidgets3.0/include/nogui/wx/setup.h
+@@ -1108,7 +1108,7 @@
+ #define HAVE_SYS_SELECT_H 1
+ 
+ /* Define if you have abi::__forced_unwind in your <cxxabi.h>. */
+-#define HAVE_ABI_FORCEDUNWIND 1
++/*#define HAVE_ABI_FORCEDUNWIND 1*/
+ 
+ /* Define if fdopen is available.  */
+ #define HAVE_FDOPEN 1
diff --git a/emulators/libretro-pcsx2/files/patch-CMakeLists.txt b/emulators/libretro-pcsx2/files/patch-CMakeLists.txt
new file mode 100644
index 000000000000..233cd0e95aa3
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-CMakeLists.txt
@@ -0,0 +1,14 @@
+--- CMakeLists.txt.orig	2020-10-29 23:31:05 UTC
++++ CMakeLists.txt
+@@ -44,7 +44,10 @@ if (LIBRETRO)
+    set(BUILD_REPLAY_LOADERS FALSE)
+ #   add_definitions(-D__LIBRETRO__ -DDISABLE_RECORDING)
+ #add_definitions(-D__LIBRETRO__ -DDISABLE_RECORDING -DwxUSE_UNICODE=0)
+-add_definitions(-D__LIBRETRO__ -DDISABLE_RECORDING -DwxUSE_GUI=0)
++message("wxWidgets_INCLUDE_DIRS: ${wxWidgets_INCLUDE_DIRS}")
++include_directories(${wxWidgets_INCLUDE_DIRS})
++#include_directories(${gdk_INCLUDE_DIRS})
++add_definitions(-D__LIBRETRO__ -DDISABLE_RECORDING -DwxUSE_GUI=0 -I${gtk_INCLUDE_DIR} -D__USE_ISOC11)
+ endif()
+ 
+ if(NOT NO_TRANSLATION)
diff --git a/emulators/libretro-pcsx2/files/patch-common_include_Utilities_General.h b/emulators/libretro-pcsx2/files/patch-common_include_Utilities_General.h
new file mode 100644
index 000000000000..5a9326ab92fe
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-common_include_Utilities_General.h
@@ -0,0 +1,11 @@
+--- common/include/Utilities/General.h.orig	2020-10-29 23:31:05 UTC
++++ common/include/Utilities/General.h
+@@ -257,7 +257,7 @@ void MemProtectStatic(u8 (&arr)[size], const PageProte
+ 
+ // Safe version of Munmap -- NULLs the pointer variable immediately after free'ing it.
+ #define SafeSysMunmap(ptr, size) \
+-    ((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = NULL))
++    ((void)(HostSys::Munmap((uptr)(ptr), size), (ptr) = 0))
+ 
+ extern void InitCPUTicks();
+ extern u64 GetTickFrequency();
diff --git a/emulators/libretro-pcsx2/files/patch-pcsx2_SPU2_spu2.cpp b/emulators/libretro-pcsx2/files/patch-pcsx2_SPU2_spu2.cpp
new file mode 100644
index 000000000000..5eba4c5b24db
--- /dev/null
+++ b/emulators/libretro-pcsx2/files/patch-pcsx2_SPU2_spu2.cpp
@@ -0,0 +1,14 @@
+--- pcsx2/SPU2/spu2.cpp.orig	2020-10-29 23:31:05 UTC
++++ pcsx2/SPU2/spu2.cpp
+@@ -17,7 +17,10 @@
+ #include "Global.h"
+ #include "spu2.h"
+ #include "Dma.h"
+-#ifdef __linux__
++#ifdef __BSD__
++#include "Linux/Dialogs.h"
++#include "Linux/Config.h"
++#elif defined(__linux__)
+ #include "Linux/Dialogs.h"
+ #include "Linux/Config.h"
+ #elif defined(_WIN32)
diff --git a/emulators/libretro-pcsx2/pkg-descr b/emulators/libretro-pcsx2/pkg-descr
new file mode 100644
index 000000000000..81a1235957f0
--- /dev/null
+++ b/emulators/libretro-pcsx2/pkg-descr
@@ -0,0 +1,9 @@
+Standalone port of pcsx2 to libretro.
+
+PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its
+purpose is to emulate the PS2's hardware, using a combination of MIPS
+CPU Interpreters, Recompilers and a Virtual Machine which manages
+hardware states and PS2 system memory. This allows you to play PS2
+games on your PC, with many additional features and benefits.
+
+WWW: https://github.com/libretro/pcsx2