mirror of
https://github.com/libretro/Play-.git
synced 2024-11-23 08:49:44 +00:00
commit
884ae3b96c
27
.travis.sh
27
.travis.sh
@ -42,10 +42,21 @@ travis_before_install()
|
||||
travis_script()
|
||||
{
|
||||
if [ "$TARGET_OS" = "Android" ]; then
|
||||
if [ "$BUILD_LIBRETRO" = "yes" ]; then
|
||||
CMAKE_PATH=/usr/local/android-sdk/cmake/3.10.2.4988404
|
||||
export PATH=${CMAKE_PATH}/bin:$PATH
|
||||
export NINJA_EXE=${CMAKE_PATH}/bin/ninja
|
||||
export ANDROID_NDK=/usr/local/android-sdk/ndk/20.0.5594570
|
||||
export ANDROID_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake
|
||||
pushd build_retro
|
||||
bash android_build.sh
|
||||
popd
|
||||
else
|
||||
pushd build_android
|
||||
./gradlew
|
||||
./gradlew assembleRelease
|
||||
popd
|
||||
fi
|
||||
elif [ "$TARGET_OS" = "Linux_Clang_Format" ]; then
|
||||
set +e
|
||||
find ./Source/ ./tools/ -iname *.h -o -iname *.cpp -o -iname *.m -iname *.mm | xargs clang-format-6.0 -i
|
||||
@ -69,7 +80,7 @@ travis_script()
|
||||
if [ "$CXX" = "g++" ]; then export CXX="g++-9" CC="gcc-9"; fi
|
||||
source /opt/qt512/bin/qt512-env.sh || true
|
||||
export PATH=$PATH:/opt/qt512/lib/cmake
|
||||
cmake .. -G"$BUILD_TYPE" -DCMAKE_INSTALL_PREFIX=./appdir/usr;
|
||||
cmake .. -G"$BUILD_TYPE" -DCMAKE_INSTALL_PREFIX=./appdir/usr -DBUILD_LIBRETRO_CORE=yes;
|
||||
cmake --build .
|
||||
ctest
|
||||
cmake --build . --target install
|
||||
@ -91,13 +102,13 @@ travis_script()
|
||||
fi
|
||||
elif [ "$TARGET_OS" = "OSX" ]; then
|
||||
export CMAKE_PREFIX_PATH="$(brew --prefix qt5)"
|
||||
cmake .. -G"$BUILD_TYPE"
|
||||
cmake .. -G"$BUILD_TYPE" -DBUILD_LIBRETRO_CORE=yes
|
||||
cmake --build . --config Release
|
||||
ctest -C Release
|
||||
$(brew --prefix qt5)/bin/macdeployqt Source/ui_qt/Release/Play.app
|
||||
appdmg ../installer_macosx/spec.json Play.dmg
|
||||
elif [ "$TARGET_OS" = "IOS" ]; then
|
||||
cmake .. -G"$BUILD_TYPE" -DCMAKE_TOOLCHAIN_FILE=../deps/Dependencies/cmake-ios/ios.cmake -DTARGET_IOS=ON -DBUILD_PSFPLAYER=ON
|
||||
cmake .. -G"$BUILD_TYPE" -DCMAKE_TOOLCHAIN_FILE=../deps/Dependencies/cmake-ios/ios.cmake -DTARGET_IOS=ON -DBUILD_PSFPLAYER=ON -DBUILD_LIBRETRO_CORE=yes
|
||||
cmake --build . --config Release
|
||||
codesign -s "-" Source/ui_ios/Release-iphoneos/Play.app
|
||||
pushd ..
|
||||
@ -125,21 +136,31 @@ travis_before_deploy()
|
||||
if [ "$TARGET_OS" = "Linux" ]; then
|
||||
if [ "$TARGET_ARCH" = "x86_64" ]; then
|
||||
cp ../../build/Play*.AppImage .
|
||||
cp ../../build/Source/ui_libretro/play_libretro.so play_libretro_linux-x86_64.so
|
||||
else
|
||||
cp ../../build/Source/ui_libretro/play_libretro.so play_libretro_linux-ARM64.so
|
||||
fi;
|
||||
fi;
|
||||
if [ "$TARGET_OS" = "Android" ]; then
|
||||
if [ "$BUILD_LIBRETRO" = "yes" ]; then
|
||||
cp ../../build_retro/play_* .
|
||||
ABI_LIST="arm64-v8a armeabi-v7a x86 x86_64"
|
||||
else
|
||||
cp ../../build_android/build/outputs/apk/release/Play-release-unsigned.apk .
|
||||
export ANDROID_BUILD_TOOLS=$ANDROID_HOME/build-tools/28.0.3
|
||||
$ANDROID_BUILD_TOOLS/zipalign -v -p 4 Play-release-unsigned.apk Play-release.apk
|
||||
$ANDROID_BUILD_TOOLS/apksigner sign --ks ../../installer_android/deploy.keystore --ks-key-alias deploy --ks-pass env:ANDROID_KEYSTORE_PASS --key-pass env:ANDROID_KEYSTORE_PASS Play-release.apk
|
||||
fi
|
||||
fi;
|
||||
if [ "$TARGET_OS" = "OSX" ]; then
|
||||
cp ../../build/Play.dmg .
|
||||
cp ../../build/Source/ui_libretro/Release/play_libretro.dylib play_libretro_macOS-x86_64.dylib
|
||||
fi;
|
||||
if [ "$TARGET_OS" = "IOS" ]; then
|
||||
cp ../../installer_ios/Play.ipa .
|
||||
cp ../../installer_ios/Play.deb .
|
||||
cp ../../installer_ios/Packages.bz2 .
|
||||
cp ../../build/Source/ui_libretro/Release/play_libretro.dylib play_libretro_iOS-FAT.dylib
|
||||
fi;
|
||||
popd
|
||||
popd
|
||||
|
14
.travis.yml
14
.travis.yml
@ -43,6 +43,20 @@ matrix:
|
||||
- build-tools-28.0.3
|
||||
- android-28
|
||||
- extra-android-m2repository
|
||||
- os: linux
|
||||
dist: trusty
|
||||
language: android
|
||||
sudo: required
|
||||
env:
|
||||
- TARGET_OS=Android
|
||||
- BUILD_LIBRETRO=yes
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-28.0.3
|
||||
- android-28
|
||||
- extra-android-m2repository
|
||||
|
||||
language: cpp
|
||||
|
||||
|
@ -18,6 +18,7 @@ set(BUILD_PSFPLAYER OFF CACHE BOOL "Build PsfPlayer")
|
||||
set(BUILD_TESTS ON CACHE BOOL "Build Tests")
|
||||
set(USE_AOT_CACHE OFF CACHE BOOL "Use AOT block cache")
|
||||
set(BUILD_AOT_CACHE OFF CACHE BOOL "Build AOT block cache (for PsfPlayer only)")
|
||||
set(BUILD_LIBRETRO_CORE OFF CACHE BOOL "Build Libretro Core")
|
||||
|
||||
set(PROJECT_NAME "Play!")
|
||||
set(PROJECT_Version 0.30)
|
||||
@ -35,6 +36,13 @@ set(PROJECT_LIBS)
|
||||
|
||||
include(PrecompiledHeader)
|
||||
|
||||
if(BUILD_LIBRETRO_CORE)
|
||||
if(NOT MSVC)
|
||||
add_compile_options("-fPIC")
|
||||
endif()
|
||||
add_subdirectory(Source/ui_libretro)
|
||||
endif()
|
||||
|
||||
if(BUILD_PLAY)
|
||||
if(TARGET_PLATFORM_UNIX OR TARGET_PLATFORM_MACOS OR TARGET_PLATFORM_WIN32 OR USE_QT)
|
||||
add_subdirectory(Source/ui_qt/)
|
||||
|
@ -539,6 +539,11 @@ void CPS2VM::CreateSoundHandlerImpl(const CSoundHandler::FactoryFunction& factor
|
||||
m_soundHandler = factoryFunction();
|
||||
}
|
||||
|
||||
CSoundHandler* CPS2VM::GetSoundHandler()
|
||||
{
|
||||
return m_soundHandler;
|
||||
}
|
||||
|
||||
void CPS2VM::DestroySoundHandlerImpl()
|
||||
{
|
||||
if(m_soundHandler == nullptr) return;
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
void DestroyPadHandler();
|
||||
|
||||
void CreateSoundHandler(const CSoundHandler::FactoryFunction&);
|
||||
CSoundHandler* GetSoundHandler();
|
||||
void DestroySoundHandler();
|
||||
void ReloadSpuBlockCount();
|
||||
|
||||
|
@ -46,14 +46,14 @@ CGSH_Direct3D9::CGSH_Direct3D9(Framework::Win32::CWindow* outputWindow)
|
||||
Framework::CBitmap CGSH_Direct3D9::GetFramebuffer(uint64 frameReg)
|
||||
{
|
||||
Framework::CBitmap result;
|
||||
m_mailBox.SendCall([&]() { result = GetFramebufferImpl(frameReg); }, true);
|
||||
SendGSCall([&]() { result = GetFramebufferImpl(frameReg); }, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
Framework::CBitmap CGSH_Direct3D9::GetTexture(uint64 tex0Reg, uint32 maxMip, uint64 miptbp1Reg, uint64 miptbp2Reg, uint32 mipLevel)
|
||||
{
|
||||
Framework::CBitmap result;
|
||||
m_mailBox.SendCall([&]() { result = GetTextureImpl(tex0Reg, maxMip, miptbp1Reg, miptbp2Reg, mipLevel); }, true);
|
||||
SendGSCall([&]() { result = GetTextureImpl(tex0Reg, maxMip, miptbp1Reg, miptbp2Reg, mipLevel); }, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,9 @@ static uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a)
|
||||
return (a << 24) | (b << 16) | (g << 8) | (r);
|
||||
}
|
||||
|
||||
CGSH_OpenGL::CGSH_OpenGL()
|
||||
: m_pCvtBuffer(nullptr)
|
||||
CGSH_OpenGL::CGSH_OpenGL(bool gsThreaded)
|
||||
: CGSHandler(gsThreaded)
|
||||
, m_pCvtBuffer(nullptr)
|
||||
{
|
||||
RegisterPreferences();
|
||||
LoadPreferences();
|
||||
@ -292,7 +293,7 @@ void CGSH_OpenGL::FlipImpl()
|
||||
void CGSH_OpenGL::LoadState(Framework::CZipArchiveReader& archive)
|
||||
{
|
||||
CGSHandler::LoadState(archive);
|
||||
m_mailBox.SendCall(
|
||||
SendGSCall(
|
||||
[this]() {
|
||||
m_textureCache.InvalidateRange(0, RAMSIZE);
|
||||
});
|
||||
|
@ -22,7 +22,7 @@
|
||||
class CGSH_OpenGL : public CGSHandler
|
||||
{
|
||||
public:
|
||||
CGSH_OpenGL();
|
||||
CGSH_OpenGL(bool = true);
|
||||
virtual ~CGSH_OpenGL();
|
||||
|
||||
static void RegisterPreferences();
|
||||
|
@ -62,13 +62,14 @@ struct MASSIVEWRITE_INFO
|
||||
CGSHandler::RegisterWriteList writes;
|
||||
};
|
||||
|
||||
CGSHandler::CGSHandler()
|
||||
CGSHandler::CGSHandler(bool gsThreaded)
|
||||
: m_threadDone(false)
|
||||
, m_drawCallCount(0)
|
||||
, m_pCLUT(nullptr)
|
||||
, m_pRAM(nullptr)
|
||||
, m_frameDump(nullptr)
|
||||
, m_loggingEnabled(true)
|
||||
, m_gsThreaded(gsThreaded)
|
||||
{
|
||||
RegisterPreferences();
|
||||
|
||||
@ -100,13 +101,19 @@ CGSHandler::CGSHandler()
|
||||
|
||||
ResetBase();
|
||||
|
||||
if(m_gsThreaded)
|
||||
{
|
||||
m_thread = std::thread([&]() { ThreadProc(); });
|
||||
}
|
||||
}
|
||||
|
||||
CGSHandler::~CGSHandler()
|
||||
{
|
||||
m_mailBox.SendCall([this]() { m_threadDone = true; });
|
||||
if(m_gsThreaded)
|
||||
{
|
||||
SendGSCall([this]() { m_threadDone = true; });
|
||||
m_thread.join();
|
||||
}
|
||||
delete[] m_pRAM;
|
||||
delete[] m_pCLUT;
|
||||
}
|
||||
@ -118,7 +125,7 @@ void CGSHandler::RegisterPreferences()
|
||||
|
||||
void CGSHandler::NotifyPreferencesChanged()
|
||||
{
|
||||
m_mailBox.SendCall([this]() { NotifyPreferencesChangedImpl(); });
|
||||
SendGSCall([this]() { NotifyPreferencesChangedImpl(); });
|
||||
}
|
||||
|
||||
void CGSHandler::SetIntc(CINTC* intc)
|
||||
@ -129,7 +136,7 @@ void CGSHandler::SetIntc(CINTC* intc)
|
||||
void CGSHandler::Reset()
|
||||
{
|
||||
ResetBase();
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::ResetImpl, this), true);
|
||||
SendGSCall(std::bind(&CGSHandler::ResetImpl, this), true);
|
||||
}
|
||||
|
||||
void CGSHandler::ResetBase()
|
||||
@ -374,27 +381,28 @@ void CGSHandler::WritePrivRegister(uint32 nAddress, uint32 nData)
|
||||
|
||||
void CGSHandler::Initialize()
|
||||
{
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::InitializeImpl, this), true);
|
||||
SendGSCall(std::bind(&CGSHandler::InitializeImpl, this), true);
|
||||
}
|
||||
|
||||
void CGSHandler::Release()
|
||||
{
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::ReleaseImpl, this), true);
|
||||
SendGSCall(std::bind(&CGSHandler::ReleaseImpl, this), true);
|
||||
}
|
||||
|
||||
void CGSHandler::Flip(bool showOnly)
|
||||
{
|
||||
if(!showOnly)
|
||||
{
|
||||
m_mailBox.FlushCalls();
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::MarkNewFrame, this));
|
||||
SendGSCall([]() {}, true);
|
||||
SendGSCall(std::bind(&CGSHandler::MarkNewFrame, this));
|
||||
}
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::FlipImpl, this), true);
|
||||
SendGSCall(std::bind(&CGSHandler::FlipImpl, this), true, true);
|
||||
}
|
||||
|
||||
void CGSHandler::FlipImpl()
|
||||
{
|
||||
OnFlipComplete();
|
||||
m_flipped = true;
|
||||
}
|
||||
|
||||
void CGSHandler::MarkNewFrame()
|
||||
@ -428,7 +436,7 @@ void CGSHandler::SetSMODE2(uint64 value)
|
||||
|
||||
void CGSHandler::WriteRegister(uint8 registerId, uint64 value)
|
||||
{
|
||||
m_mailBox.SendCall(std::bind(&CGSHandler::WriteRegisterImpl, this, registerId, value));
|
||||
SendGSCall(std::bind(&CGSHandler::WriteRegisterImpl, this, registerId, value));
|
||||
}
|
||||
|
||||
void CGSHandler::FeedImageData(const void* data, uint32 length)
|
||||
@ -440,7 +448,7 @@ void CGSHandler::FeedImageData(const void* data, uint32 length)
|
||||
|
||||
std::vector<uint8> imageData(length + 0x10);
|
||||
memcpy(imageData.data(), data, length);
|
||||
m_mailBox.SendCall(
|
||||
SendGSCall(
|
||||
[this, imageData = std::move(imageData), length]() {
|
||||
FeedImageDataImpl(imageData.data(), length);
|
||||
});
|
||||
@ -448,7 +456,7 @@ void CGSHandler::FeedImageData(const void* data, uint32 length)
|
||||
|
||||
void CGSHandler::ReadImageData(void* data, uint32 length)
|
||||
{
|
||||
m_mailBox.SendCall([this, data, length]() { ReadImageDataImpl(data, length); }, true);
|
||||
SendGSCall([this, data, length]() { ReadImageDataImpl(data, length); }, true);
|
||||
}
|
||||
|
||||
void CGSHandler::WriteRegisterMassively(RegisterWriteList registerWrites, const CGsPacketMetadata* metadata)
|
||||
@ -500,7 +508,7 @@ void CGSHandler::WriteRegisterMassively(RegisterWriteList registerWrites, const
|
||||
}
|
||||
#endif
|
||||
|
||||
m_mailBox.SendCall(
|
||||
SendGSCall(
|
||||
[this, massiveWrite = std::move(massiveWrite)]() {
|
||||
WriteRegisterMassivelyImpl(massiveWrite);
|
||||
});
|
||||
@ -1728,6 +1736,30 @@ void CGSHandler::ThreadProc()
|
||||
}
|
||||
}
|
||||
|
||||
void CGSHandler::SendGSCall(const CMailBox::FunctionType& function, bool waitForCompletion, bool forceWaitForCompletion)
|
||||
{
|
||||
if(!m_gsThreaded)
|
||||
{
|
||||
waitForCompletion = false;
|
||||
}
|
||||
waitForCompletion |= forceWaitForCompletion;
|
||||
m_mailBox.SendCall(function, waitForCompletion);
|
||||
}
|
||||
|
||||
void CGSHandler::ProcessSingleFrame()
|
||||
{
|
||||
assert(!m_gsThreaded);
|
||||
while(!m_flipped)
|
||||
{
|
||||
m_mailBox.WaitForCall();
|
||||
while(m_mailBox.IsPending() && !m_flipped)
|
||||
{
|
||||
m_mailBox.ReceiveCall();
|
||||
}
|
||||
}
|
||||
m_flipped = false;
|
||||
}
|
||||
|
||||
Framework::CBitmap CGSHandler::GetScreenshot()
|
||||
{
|
||||
throw std::runtime_error("Screenshot feature is not implemented in current backend.");
|
||||
|
@ -704,7 +704,7 @@ public:
|
||||
typedef Framework::CSignal<void()> FlipCompleteEvent;
|
||||
typedef Framework::CSignal<void(uint32)> NewFrameEvent;
|
||||
|
||||
CGSHandler();
|
||||
CGSHandler(bool = true);
|
||||
virtual ~CGSHandler();
|
||||
|
||||
static void RegisterPreferences();
|
||||
@ -763,6 +763,7 @@ public:
|
||||
bool GetCrtIsFrameMode() const;
|
||||
|
||||
virtual Framework::CBitmap GetScreenshot();
|
||||
void ProcessSingleFrame();
|
||||
|
||||
FlipCompleteEvent OnFlipComplete;
|
||||
NewFrameEvent OnNewFrame;
|
||||
@ -952,6 +953,7 @@ protected:
|
||||
void ReadCLUT8(const TEX0&);
|
||||
|
||||
static bool IsCompatibleFramebufferPSM(unsigned int, unsigned int);
|
||||
void SendGSCall(const CMailBox::FunctionType&, bool = false, bool = false);
|
||||
|
||||
bool m_loggingEnabled;
|
||||
|
||||
@ -983,9 +985,13 @@ protected:
|
||||
std::thread m_thread;
|
||||
std::recursive_mutex m_registerMutex;
|
||||
std::atomic<int> m_transferCount;
|
||||
CMailBox m_mailBox;
|
||||
bool m_threadDone;
|
||||
CFrameDump* m_frameDump;
|
||||
bool m_drawEnabled = true;
|
||||
CINTC* m_intc = nullptr;
|
||||
bool m_gsThreaded = true;
|
||||
bool m_flipped = false;
|
||||
|
||||
private:
|
||||
CMailBox m_mailBox;
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ void CGSH_OpenGLAndroid::PresentBackbuffer()
|
||||
void CGSH_OpenGLAndroid::SetWindow(NativeWindowType window)
|
||||
{
|
||||
m_window = window;
|
||||
m_mailBox.SendCall(
|
||||
SendGSCall(
|
||||
[this]() {
|
||||
SetupContext();
|
||||
},
|
||||
|
60
Source/ui_libretro/CMakeLists.txt
Normal file
60
Source/ui_libretro/CMakeLists.txt
Normal file
@ -0,0 +1,60 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../deps/Dependencies/cmake-modules
|
||||
${CMAKE_MODULE_PATH}
|
||||
)
|
||||
include(Header)
|
||||
|
||||
project(Play_Libretro_Core)
|
||||
|
||||
add_definitions(-DPLAY_VERSION="${PROJECT_Version}")
|
||||
|
||||
if(NOT TARGET PlayCore)
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Source
|
||||
)
|
||||
endif()
|
||||
list(APPEND PROJECT_LIBS PlayCore)
|
||||
|
||||
if(NOT TARGET gsh_opengl)
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../gs/GSH_OpenGL
|
||||
${CMAKE_CURRENT_BINARY_DIR}/gs/GSH_OpenGL
|
||||
)
|
||||
endif()
|
||||
list(INSERT PROJECT_LIBS 0 gsh_opengl)
|
||||
|
||||
set(SRC
|
||||
main_libretro.cpp
|
||||
GSH_OpenGL_Libretro.cpp
|
||||
GSH_OpenGL_Libretro.h
|
||||
PH_Libretro_Input.cpp
|
||||
PH_Libretro_Input.h
|
||||
SH_LibreAudio.cpp
|
||||
SH_LibreAudio.h
|
||||
)
|
||||
|
||||
if(TARGET_PLATFORM_ANDROID)
|
||||
list(APPEND PROJECT_LIBS android log GLESv3 EGL)
|
||||
elseif(TARGET_PLATFORM_IOS)
|
||||
list(APPEND PROJECT_LIBS "-ObjC -lsqlite3 -framework OpenGLES")
|
||||
endif()
|
||||
|
||||
add_library(play_libretro SHARED ${SRC})
|
||||
target_include_directories(play_libretro PRIVATE
|
||||
./
|
||||
../../
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
if(TARGET_PLATFORM_ANDROID)
|
||||
set_target_properties(play_libretro PROPERTIES SUFFIX "_android.so")
|
||||
endif()
|
||||
if(TARGET_PLATFORM_IOS)
|
||||
set_target_properties(play_libretro PROPERTIES SUFFIX "_ios.dylib")
|
||||
endif()
|
||||
|
||||
target_link_libraries(play_libretro ${PROJECT_LIBS})
|
||||
set_target_properties(play_libretro PROPERTIES PREFIX "")
|
114
Source/ui_libretro/GSH_OpenGL_Libretro.cpp
Normal file
114
Source/ui_libretro/GSH_OpenGL_Libretro.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
#include "GSH_OpenGL_Libretro.h"
|
||||
#include "Log.h"
|
||||
|
||||
#define LOG_NAME "LIBRETRO"
|
||||
|
||||
extern int g_res_factor;
|
||||
extern CGSHandler::PRESENTATION_MODE g_presentation_mode;
|
||||
extern retro_video_refresh_t g_video_cb;
|
||||
extern struct retro_hw_render_callback g_hw_render;
|
||||
|
||||
CGSH_OpenGL_Libretro::CGSH_OpenGL_Libretro()
|
||||
: CGSH_OpenGL(false)
|
||||
{
|
||||
}
|
||||
|
||||
CGSH_OpenGL_Libretro::~CGSH_OpenGL_Libretro()
|
||||
{
|
||||
}
|
||||
|
||||
CGSH_OpenGL::FactoryFunction CGSH_OpenGL_Libretro::GetFactoryFunction()
|
||||
{
|
||||
return []() { return new CGSH_OpenGL_Libretro(); };
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::InitializeImpl()
|
||||
{
|
||||
fprintf(stderr, "%s\n", __FUNCTION__);
|
||||
|
||||
#if defined(USE_GLEW)
|
||||
glewExperimental = GL_TRUE;
|
||||
auto result = glewInit();
|
||||
CLog::GetInstance().Warn(LOG_NAME, "glewInit %d\n", result == GLEW_OK);
|
||||
assert(result == GLEW_OK);
|
||||
if(result != GLEW_OK)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", glewGetErrorString(result));
|
||||
CLog::GetInstance().Warn(LOG_NAME, "Error: %s\n", glewGetErrorString(result));
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(g_hw_render.get_current_framebuffer)
|
||||
m_presentFramebuffer = g_hw_render.get_current_framebuffer();
|
||||
|
||||
UpdatePresentationImpl();
|
||||
|
||||
CGSH_OpenGL::InitializeImpl();
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::UpdatePresentation()
|
||||
{
|
||||
SendGSCall([this]() { UpdatePresentationImpl(); });
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::UpdatePresentationImpl()
|
||||
{
|
||||
PRESENTATION_PARAMS presentationParams;
|
||||
presentationParams.mode = g_presentation_mode;
|
||||
presentationParams.windowWidth = GetCrtWidth() * g_res_factor;
|
||||
presentationParams.windowHeight = GetCrtHeight() * g_res_factor;
|
||||
|
||||
SetPresentationParams(presentationParams);
|
||||
NotifyPreferencesChanged();
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::FlushMailBox()
|
||||
{
|
||||
bool isFlushed = false;
|
||||
SendGSCall([&]() {
|
||||
isFlushed = true;
|
||||
},
|
||||
true);
|
||||
while(!isFlushed)
|
||||
{
|
||||
// Wait for flush to complete
|
||||
ProcessSingleFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::Reset()
|
||||
{
|
||||
FlushMailBox();
|
||||
ResetBase();
|
||||
CGSH_OpenGL::ReleaseImpl();
|
||||
InitializeImpl();
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::Release()
|
||||
{
|
||||
FlushMailBox();
|
||||
ResetBase();
|
||||
CGSH_OpenGL::ReleaseImpl();
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::FlipImpl()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(g_hw_render.get_current_framebuffer)
|
||||
m_presentFramebuffer = g_hw_render.get_current_framebuffer();
|
||||
else
|
||||
return;
|
||||
|
||||
CGSH_OpenGL::FlipImpl();
|
||||
}
|
||||
|
||||
void CGSH_OpenGL_Libretro::PresentBackbuffer()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(g_video_cb)
|
||||
g_video_cb(RETRO_HW_FRAME_BUFFER_VALID, GetCrtWidth() * g_res_factor, GetCrtHeight() * g_res_factor, 0);
|
||||
}
|
24
Source/ui_libretro/GSH_OpenGL_Libretro.h
Normal file
24
Source/ui_libretro/GSH_OpenGL_Libretro.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "gs/GSH_OpenGL/GSH_OpenGL.h"
|
||||
#include "libretro.h"
|
||||
|
||||
class CGSH_OpenGL_Libretro : public CGSH_OpenGL
|
||||
{
|
||||
public:
|
||||
CGSH_OpenGL_Libretro();
|
||||
virtual ~CGSH_OpenGL_Libretro();
|
||||
|
||||
static FactoryFunction GetFactoryFunction();
|
||||
|
||||
void InitializeImpl() override;
|
||||
void FlipImpl() override;
|
||||
void Reset();
|
||||
void Release();
|
||||
void PresentBackbuffer() override;
|
||||
void UpdatePresentation();
|
||||
void FlushMailBox();
|
||||
|
||||
private:
|
||||
void UpdatePresentationImpl();
|
||||
};
|
71
Source/ui_libretro/PH_Libretro_Input.cpp
Normal file
71
Source/ui_libretro/PH_Libretro_Input.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "PH_Libretro_Input.h"
|
||||
|
||||
extern bool libretro_supports_bitmasks;
|
||||
extern retro_input_poll_t g_input_poll_cb;
|
||||
extern retro_input_state_t g_input_state_cb;
|
||||
extern std::map<int, int> g_ds2_to_retro_btn_map;
|
||||
|
||||
void CPH_Libretro_Input::UpdateInputState()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_input_mutex);
|
||||
g_input_poll_cb();
|
||||
|
||||
if(libretro_supports_bitmasks)
|
||||
{
|
||||
m_btns_state = g_input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_btns_state = 0;
|
||||
for(unsigned int i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
|
||||
{
|
||||
if(g_input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i))
|
||||
m_btns_state |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i <= PS2::CControllerInfo::ANALOG_RIGHT_Y + 1; i++)
|
||||
{
|
||||
auto currentButtonId = static_cast<PS2::CControllerInfo::BUTTON>(i);
|
||||
if(PS2::CControllerInfo::IsAxis(currentButtonId))
|
||||
{
|
||||
int index;
|
||||
if(i < 2)
|
||||
index = RETRO_DEVICE_INDEX_ANALOG_LEFT;
|
||||
else
|
||||
index = RETRO_DEVICE_INDEX_ANALOG_RIGHT;
|
||||
|
||||
float value = g_input_state_cb(0, RETRO_DEVICE_ANALOG, index, g_ds2_to_retro_btn_map[currentButtonId]);
|
||||
uint8 val = static_cast<int8>((value / 0xFF) + 0.5) + 0x7F;
|
||||
if(val > 0x7F - 5 && val < 0x7F + 5)
|
||||
val = 0x7F;
|
||||
m_axis_btn_state[currentButtonId] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPH_Libretro_Input::Update(uint8* ram)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_input_mutex);
|
||||
for(auto* listener : m_listeners)
|
||||
{
|
||||
for(unsigned int i = 0; i < PS2::CControllerInfo::MAX_BUTTONS; i++)
|
||||
{
|
||||
auto currentButtonId = static_cast<PS2::CControllerInfo::BUTTON>(i);
|
||||
if(PS2::CControllerInfo::IsAxis(currentButtonId))
|
||||
{
|
||||
listener->SetAxisState(0, currentButtonId, m_axis_btn_state[currentButtonId], ram);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 val = m_btns_state & (1 << g_ds2_to_retro_btn_map[currentButtonId]);
|
||||
listener->SetButtonState(0, currentButtonId, val != 0, ram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CPadHandler::FactoryFunction CPH_Libretro_Input::GetFactoryFunction()
|
||||
{
|
||||
return []() { return new CPH_Libretro_Input(); };
|
||||
}
|
25
Source/ui_libretro/PH_Libretro_Input.h
Normal file
25
Source/ui_libretro/PH_Libretro_Input.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include "PadHandler.h"
|
||||
// #include "InputBindingManager.h"
|
||||
#include "libretro.h"
|
||||
|
||||
class CPH_Libretro_Input : public CPadHandler
|
||||
{
|
||||
public:
|
||||
CPH_Libretro_Input() = default;
|
||||
virtual ~CPH_Libretro_Input() = default;
|
||||
|
||||
void Update(uint8*) override;
|
||||
|
||||
static FactoryFunction GetFactoryFunction();
|
||||
|
||||
void UpdateInputState();
|
||||
|
||||
private:
|
||||
int16 m_btns_state = 0;
|
||||
uint8 m_axis_btn_state[4] = {0x7F};
|
||||
std::mutex m_input_mutex;
|
||||
};
|
43
Source/ui_libretro/SH_LibreAudio.cpp
Normal file
43
Source/ui_libretro/SH_LibreAudio.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "SH_LibreAudio.h"
|
||||
#include "libretro.h"
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
extern retro_audio_sample_batch_t g_set_audio_sample_batch_cb;
|
||||
std::mutex m_buffer_lock;
|
||||
|
||||
CSoundHandler* CSH_LibreAudio::HandlerFactory()
|
||||
{
|
||||
return new CSH_LibreAudio();
|
||||
}
|
||||
|
||||
void CSH_LibreAudio::Write(int16* buffer, unsigned int sampleCount, unsigned int sampleRate)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_buffer_lock);
|
||||
m_buffer.resize(sampleCount * sizeof(int16));
|
||||
memcpy(m_buffer.data(), buffer, sampleCount * sizeof(int16));
|
||||
}
|
||||
|
||||
void CSH_LibreAudio::ProcessBuffer()
|
||||
{
|
||||
if(!m_buffer.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_buffer_lock);
|
||||
if(g_set_audio_sample_batch_cb)
|
||||
g_set_audio_sample_batch_cb(m_buffer.data(), m_buffer.size() / (2 * sizeof(int16)));
|
||||
m_buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool CSH_LibreAudio::HasFreeBuffers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSH_LibreAudio::Reset()
|
||||
{
|
||||
}
|
||||
|
||||
void CSH_LibreAudio::RecycleBuffers()
|
||||
{
|
||||
}
|
26
Source/ui_libretro/SH_LibreAudio.h
Normal file
26
Source/ui_libretro/SH_LibreAudio.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "tools/PsfPlayer/Source/SoundHandler.h"
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
class CSH_LibreAudio : public CSoundHandler
|
||||
{
|
||||
public:
|
||||
CSH_LibreAudio() = default;
|
||||
|
||||
static CSoundHandler* HandlerFactory();
|
||||
|
||||
void Reset() override;
|
||||
void Write(int16*, unsigned int, unsigned int) override;
|
||||
bool HasFreeBuffers() override;
|
||||
void RecycleBuffers() override;
|
||||
|
||||
void ProcessBuffer();
|
||||
|
||||
private:
|
||||
std::vector<int16> m_buffer;
|
||||
std::mutex m_buffer_lock;
|
||||
};
|
2552
Source/ui_libretro/libretro.h
Normal file
2552
Source/ui_libretro/libretro.h
Normal file
File diff suppressed because it is too large
Load Diff
589
Source/ui_libretro/main_libretro.cpp
Normal file
589
Source/ui_libretro/main_libretro.cpp
Normal file
@ -0,0 +1,589 @@
|
||||
#include "libretro.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "AppConfig.h"
|
||||
#include "PS2VM.h"
|
||||
|
||||
#include "PS2VM_Preferences.h"
|
||||
#include "GSH_OpenGL_Libretro.h"
|
||||
#include "SH_LibreAudio.h"
|
||||
#include "PH_Libretro_Input.h"
|
||||
|
||||
#include "PathUtils.h"
|
||||
#include "PtrStream.h"
|
||||
#include "MemStream.h"
|
||||
|
||||
#include "filesystem_def.h"
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#define LOG_NAME "LIBRETRO"
|
||||
|
||||
static CPS2VM* m_virtualMachine = nullptr;
|
||||
static bool first_run = false;
|
||||
|
||||
bool libretro_supports_bitmasks = false;
|
||||
retro_video_refresh_t g_video_cb;
|
||||
retro_environment_t g_environ_cb;
|
||||
retro_input_poll_t g_input_poll_cb;
|
||||
retro_input_state_t g_input_state_cb;
|
||||
retro_audio_sample_batch_t g_set_audio_sample_batch_cb;
|
||||
|
||||
std::map<int, int> g_ds2_to_retro_btn_map;
|
||||
struct retro_hw_render_callback g_hw_render
|
||||
{
|
||||
};
|
||||
|
||||
int g_res_factor = 1;
|
||||
CGSHandler::PRESENTATION_MODE g_presentation_mode = CGSHandler::PRESENTATION_MODE::PRESENTATION_MODE_FIT;
|
||||
bool g_forceBilinearTextures = false;
|
||||
|
||||
static std::vector<struct retro_variable> m_vars =
|
||||
{
|
||||
{"play_res_multi", "Resolution Multiplier; 1x|2x|4x|8x"},
|
||||
{"play_presentation_mode", "Presentation Mode; Fit Screen|Fill Screen|Original Size"},
|
||||
{"play_bilinear_filtering", "Force Bilinear Filtering; false|true"},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
enum BootType
|
||||
{
|
||||
CD,
|
||||
ELF
|
||||
};
|
||||
|
||||
struct LastOpenCommand
|
||||
{
|
||||
LastOpenCommand() = default;
|
||||
LastOpenCommand(BootType type, fs::path path)
|
||||
: type(type)
|
||||
, path(path)
|
||||
{
|
||||
}
|
||||
BootType type = BootType::CD;
|
||||
fs::path path;
|
||||
};
|
||||
|
||||
LastOpenCommand m_bootCommand;
|
||||
|
||||
unsigned retro_api_version()
|
||||
{
|
||||
return RETRO_API_VERSION;
|
||||
}
|
||||
|
||||
void SetupVideoHandler()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
auto gsHandler = m_virtualMachine->GetGSHandler();
|
||||
if(!gsHandler)
|
||||
{
|
||||
m_virtualMachine->CreateGSHandler(CGSH_OpenGL_Libretro::GetFactoryFunction());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto retro_gs = static_cast<CGSH_OpenGL_Libretro*>(gsHandler);
|
||||
retro_gs->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
static void retro_context_destroy()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void retro_context_reset()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
SetupVideoHandler();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupSoundHandler()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
m_virtualMachine->CreateSoundHandler(&CSH_LibreAudio::HandlerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupInputHandler()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(!m_virtualMachine->GetPadHandler())
|
||||
{
|
||||
static struct retro_input_descriptor descDS2[] =
|
||||
{
|
||||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Stick X"},
|
||||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Stick Y"},
|
||||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Stick X"},
|
||||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Stick Y"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Tringle"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2"},
|
||||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3"},
|
||||
{0},
|
||||
};
|
||||
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descDS2);
|
||||
|
||||
static const struct retro_controller_description controllers[] = {
|
||||
{"PS2 DualShock2", RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)},
|
||||
};
|
||||
|
||||
static const struct retro_controller_info ports[] = {
|
||||
{controllers, 1},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
|
||||
|
||||
for(unsigned int i = 0; i < PS2::CControllerInfo::MAX_BUTTONS; i++)
|
||||
{
|
||||
auto ds2_button = static_cast<PS2::CControllerInfo::BUTTON>(i);
|
||||
auto retro_button = descDS2[i].id;
|
||||
g_ds2_to_retro_btn_map[ds2_button] = retro_button;
|
||||
}
|
||||
|
||||
m_virtualMachine->CreatePadHandler(CPH_Libretro_Input::GetFactoryFunction());
|
||||
}
|
||||
}
|
||||
|
||||
void retro_get_system_info(struct retro_system_info* info)
|
||||
{
|
||||
*info = {};
|
||||
info->library_name = "Play!";
|
||||
info->library_version = PLAY_VERSION;
|
||||
info->need_fullpath = true;
|
||||
info->valid_extensions = "elf|iso|cso|isz|bin";
|
||||
}
|
||||
|
||||
void retro_get_system_av_info(struct retro_system_av_info* info)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
*info = {};
|
||||
info->timing.fps = 60.0;
|
||||
info->timing.sample_rate = 44100;
|
||||
info->geometry.base_width = 640;
|
||||
info->geometry.base_height = 448;
|
||||
info->geometry.max_width = 640 * 8;
|
||||
info->geometry.max_height = 448 * 8;
|
||||
info->geometry.aspect_ratio = 4.0 / 3.0;
|
||||
}
|
||||
|
||||
void retro_set_video_refresh(retro_video_refresh_t cb)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
g_video_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_environment(retro_environment_t cb)
|
||||
{
|
||||
g_environ_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_poll(retro_input_poll_t cb)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
g_input_poll_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_input_state(retro_input_state_t cb)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
g_input_state_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
g_set_audio_sample_batch_cb = cb;
|
||||
}
|
||||
|
||||
void retro_set_audio_sample(retro_audio_sample_t)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
unsigned retro_get_region(void)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
return RETRO_REGION_NTSC;
|
||||
}
|
||||
|
||||
size_t retro_serialize_size(void)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
return 40 * 1024 * 1024;
|
||||
}
|
||||
|
||||
bool retro_serialize(void* data, size_t size)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
try
|
||||
{
|
||||
Framework::CMemStream stateStream;
|
||||
Framework::CZipArchiveWriter archive;
|
||||
|
||||
m_virtualMachine->m_ee->SaveState(archive);
|
||||
m_virtualMachine->m_iop->SaveState(archive);
|
||||
m_virtualMachine->m_ee->m_gs->SaveState(archive);
|
||||
|
||||
archive.Write(stateStream);
|
||||
stateStream.Seek(0, Framework::STREAM_SEEK_DIRECTION::STREAM_SEEK_SET);
|
||||
stateStream.Read(data, size);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool retro_unserialize(const void* data, size_t size)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
try
|
||||
{
|
||||
Framework::CPtrStream stateStream(data, size);
|
||||
Framework::CZipArchiveReader archive(stateStream);
|
||||
|
||||
try
|
||||
{
|
||||
m_virtualMachine->m_ee->LoadState(archive);
|
||||
m_virtualMachine->m_iop->LoadState(archive);
|
||||
m_virtualMachine->m_ee->m_gs->LoadState(archive);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//Any error that occurs in the previous block is critical
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_virtualMachine->OnMachineStateChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
void* retro_get_memory_data(unsigned id)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(id == RETRO_MEMORY_SYSTEM_RAM)
|
||||
{
|
||||
return m_virtualMachine->m_ee->m_ram;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t retro_get_memory_size(unsigned id)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(id == RETRO_MEMORY_SYSTEM_RAM)
|
||||
{
|
||||
return PS2::EE_RAM_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void retro_cheat_reset(void)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char* code)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
(void)index;
|
||||
(void)enabled;
|
||||
(void)code;
|
||||
}
|
||||
|
||||
void updateVars()
|
||||
{
|
||||
for(int i = 0; i < m_vars.size() - 1; ++i)
|
||||
{
|
||||
auto item = m_vars[i];
|
||||
if(!item.key)
|
||||
continue;
|
||||
|
||||
struct retro_variable var = {nullptr};
|
||||
var.key = item.key;
|
||||
if(g_environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
bool videoUpdate = false;
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
std::string val = var.value;
|
||||
auto res_factor = std::atoi(val.substr(0, -1).c_str());
|
||||
if(res_factor != g_res_factor)
|
||||
{
|
||||
g_res_factor = res_factor;
|
||||
CAppConfig::GetInstance().SetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR, res_factor);
|
||||
videoUpdate = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
CGSHandler::PRESENTATION_MODE presentation_mode = CGSHandler::PRESENTATION_MODE::PRESENTATION_MODE_FIT;
|
||||
|
||||
std::string val(var.value);
|
||||
if(val == "Fill Screen")
|
||||
presentation_mode = CGSHandler::PRESENTATION_MODE::PRESENTATION_MODE_FILL;
|
||||
else if(val == "Original Size")
|
||||
presentation_mode = CGSHandler::PRESENTATION_MODE::PRESENTATION_MODE_ORIGINAL;
|
||||
|
||||
if(presentation_mode != g_presentation_mode)
|
||||
{
|
||||
g_presentation_mode = presentation_mode;
|
||||
CAppConfig::GetInstance().SetPreferenceInteger(PREF_CGSHANDLER_PRESENTATION_MODE, presentation_mode);
|
||||
videoUpdate = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
bool forceBilinearTextures = (std::string(var.value) == "true");
|
||||
if(forceBilinearTextures != g_forceBilinearTextures)
|
||||
{
|
||||
g_forceBilinearTextures = forceBilinearTextures;
|
||||
CAppConfig::GetInstance().SetPreferenceBoolean(PREF_CGSH_OPENGL_FORCEBILINEARTEXTURES, forceBilinearTextures);
|
||||
videoUpdate = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(videoUpdate)
|
||||
{
|
||||
if(m_virtualMachine)
|
||||
if(m_virtualMachine->GetGSHandler())
|
||||
static_cast<CGSH_OpenGL_Libretro*>(m_virtualMachine->GetGSHandler())->UpdatePresentation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkVarsUpdates()
|
||||
{
|
||||
static bool updates = true;
|
||||
if(!updates)
|
||||
g_environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updates);
|
||||
|
||||
if(updates)
|
||||
{
|
||||
updateVars();
|
||||
}
|
||||
updates = false;
|
||||
}
|
||||
|
||||
void retro_run()
|
||||
{
|
||||
// CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
checkVarsUpdates();
|
||||
|
||||
if(!first_run)
|
||||
{
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
// m_virtualMachine->Pause();
|
||||
m_virtualMachine->Reset();
|
||||
if(m_bootCommand.type == BootType::CD)
|
||||
{
|
||||
m_virtualMachine->m_ee->m_os->BootFromCDROM();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_virtualMachine->m_ee->m_os->BootFromFile(m_bootCommand.path);
|
||||
}
|
||||
m_virtualMachine->Resume();
|
||||
first_run = true;
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", "Start Game");
|
||||
}
|
||||
}
|
||||
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
auto pad = m_virtualMachine->GetPadHandler();
|
||||
if(pad)
|
||||
static_cast<CPH_Libretro_Input*>(pad)->UpdateInputState();
|
||||
|
||||
if(m_virtualMachine->GetSoundHandler())
|
||||
static_cast<CSH_LibreAudio*>(m_virtualMachine->GetSoundHandler())->ProcessBuffer();
|
||||
|
||||
if(m_virtualMachine->GetGSHandler())
|
||||
m_virtualMachine->GetGSHandler()->ProcessSingleFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void retro_reset(void)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
if(!m_virtualMachine->GetGSHandler())
|
||||
SetupVideoHandler();
|
||||
// m_virtualMachine->Pause();
|
||||
m_virtualMachine->Reset();
|
||||
m_virtualMachine->m_ee->m_os->BootFromCDROM();
|
||||
m_virtualMachine->Resume();
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", "Reset Game");
|
||||
}
|
||||
first_run = false;
|
||||
}
|
||||
|
||||
bool IsBootableExecutablePath(const fs::path& filePath)
|
||||
{
|
||||
auto extension = filePath.extension().string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
return (extension == ".elf");
|
||||
}
|
||||
|
||||
bool IsBootableDiscImagePath(const fs::path& filePath)
|
||||
{
|
||||
auto extension = filePath.extension().string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
return (extension == ".iso") ||
|
||||
(extension == ".isz") ||
|
||||
(extension == ".cso") ||
|
||||
(extension == ".bin");
|
||||
}
|
||||
|
||||
bool retro_load_game(const retro_game_info* info)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
fs::path filePath = info->path;
|
||||
if(IsBootableExecutablePath(filePath))
|
||||
{
|
||||
m_bootCommand = LastOpenCommand(BootType::ELF, filePath);
|
||||
}
|
||||
else if(IsBootableDiscImagePath(filePath))
|
||||
{
|
||||
m_bootCommand = LastOpenCommand(BootType::CD, filePath);
|
||||
CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, filePath);
|
||||
CAppConfig::GetInstance().Save();
|
||||
}
|
||||
first_run = false;
|
||||
|
||||
auto rgb = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb);
|
||||
|
||||
#ifdef GLES_COMPATIBILITY
|
||||
g_hw_render.context_type = RETRO_HW_CONTEXT_OPENGLES3;
|
||||
#else
|
||||
g_hw_render.context_type = RETRO_HW_CONTEXT_OPENGL_CORE;
|
||||
#endif
|
||||
|
||||
g_hw_render.version_major = 3;
|
||||
g_hw_render.version_minor = 2;
|
||||
g_hw_render.context_reset = retro_context_reset;
|
||||
g_hw_render.context_destroy = retro_context_destroy;
|
||||
g_hw_render.cache_context = false;
|
||||
g_hw_render.bottom_left_origin = true;
|
||||
g_hw_render.depth = true;
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT, nullptr);
|
||||
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &g_hw_render);
|
||||
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT, nullptr);
|
||||
|
||||
g_environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)m_vars.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void retro_unload_game(void)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info)
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void retro_init()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
Framework::PathUtils::SetFilesDirPath(getenv("EXTERNAL_STORAGE"));
|
||||
#endif
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(g_environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
|
||||
libretro_supports_bitmasks = true;
|
||||
|
||||
CAppConfig::GetInstance().RegisterPreferenceInteger(PREF_AUDIO_SPUBLOCKCOUNT, 22);
|
||||
|
||||
m_virtualMachine = new CPS2VM();
|
||||
m_virtualMachine->Initialize();
|
||||
|
||||
SetupInputHandler();
|
||||
SetupSoundHandler();
|
||||
first_run = false;
|
||||
}
|
||||
|
||||
void retro_deinit()
|
||||
{
|
||||
CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__);
|
||||
|
||||
if(m_virtualMachine)
|
||||
{
|
||||
// Note: since we're forced GS into running on this thread
|
||||
// we need to clear its queue, to prevent it freezing the reset of the system during delete
|
||||
auto gsHandler = m_virtualMachine->GetGSHandler();
|
||||
if(gsHandler)
|
||||
static_cast<CGSH_OpenGL_Libretro*>(gsHandler)->Release();
|
||||
|
||||
m_virtualMachine->Pause();
|
||||
m_virtualMachine->DestroyPadHandler();
|
||||
m_virtualMachine->DestroyGSHandler();
|
||||
m_virtualMachine->DestroySoundHandler();
|
||||
m_virtualMachine->Destroy();
|
||||
delete m_virtualMachine;
|
||||
m_virtualMachine = nullptr;
|
||||
}
|
||||
libretro_supports_bitmasks = false;
|
||||
}
|
@ -30,6 +30,8 @@ build_script:
|
||||
artifacts:
|
||||
- path: $(REPO_COMMIT_SHORT)\*.exe
|
||||
name: Binaries
|
||||
- path: $(REPO_COMMIT_SHORT)\play_libretro.dll
|
||||
name: Libretro_Core
|
||||
deploy:
|
||||
- provider: S3
|
||||
access_key_id: AKIAJGVKEDYESR2BIP7Q
|
||||
|
@ -5,7 +5,8 @@ mkdir build
|
||||
cd build
|
||||
|
||||
if "%BUILD_PLAY%" == "ON" (
|
||||
cmake .. -G"%BUILD_TYPE%" -T v141_xp -DUSE_QT=on -DCMAKE_PREFIX_PATH="C:\Qt\5.12\%QT_FLAVOR%"
|
||||
set BUILD_DIR=%cd%
|
||||
cmake .. -G"%BUILD_TYPE%" -T v141_xp -DUSE_QT=on -DBUILD_LIBRETRO_CORE=yes -DCMAKE_PREFIX_PATH="C:\Qt\5.12\%QT_FLAVOR%"
|
||||
if !errorlevel! neq 0 exit /b !errorlevel!
|
||||
|
||||
cmake --build . --config %CONFIG_TYPE%
|
||||
@ -21,6 +22,7 @@ if "%BUILD_PLAY%" == "ON" (
|
||||
|
||||
mkdir %REPO_COMMIT_SHORT%
|
||||
move installer_win32\*.exe %REPO_COMMIT_SHORT%
|
||||
move build\Source\ui_libretro\Release\play_libretro.dll %REPO_COMMIT_SHORT%
|
||||
)
|
||||
|
||||
if "%BUILD_PSFPLAYER%" == "ON" (
|
||||
|
29
build_retro/android_build.sh
Normal file
29
build_retro/android_build.sh
Normal file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$ANDROID_NDK" ]
|
||||
then
|
||||
echo "Please set ANDROID_NDK and run again"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
STRIP="${ANDROID_NDK}/toolchains/llvm/prebuilt/*/bin/llvm-strip"
|
||||
ABI_LIST="arm64-v8a armeabi-v7a x86 x86_64"
|
||||
for ABI in $ABI_LIST
|
||||
do
|
||||
mkdir "build_$ABI"
|
||||
pushd "build_$ABI"
|
||||
cmake ../.. -DBUILD_LIBRETRO_CORE=yes -DBUILD_PLAY=off \
|
||||
-GNinja \
|
||||
-DANDROID_ABI="${ABI}" \
|
||||
-DANDROID_NDK=${ANDROID_NDK} \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_TOOLCHAIN_FILE} \
|
||||
-DANDROID_NATIVE_API_LEVEL=19 \
|
||||
-DANDROID_STL=c++_static \
|
||||
-DANDROID_TOOLCHAIN=clang \
|
||||
-DCMAKE_MAKE_PROGRAM=${NINJA_EXE}
|
||||
|
||||
cmake --build . --target play_libretro
|
||||
${STRIP} -strip-all -o ../play_libretro_${ABI}_android.so Source/ui_libretro/play_libretro_android.so
|
||||
popd
|
||||
done
|
Loading…
Reference in New Issue
Block a user