Implemented python script running with emu_frameadvance and loop_test.py

This commit is contained in:
gfp34 2022-10-12 02:16:58 -04:00
parent 105e46edd7
commit a415977089
6 changed files with 149 additions and 0 deletions

View File

@ -0,0 +1,5 @@
import emu
while True:
print("PY: Frame")
emu.frameadvance()

View File

@ -224,6 +224,11 @@ else ()
)
endif()
# Python and pybind11 configuration
find_package(pybind11 REQUIRED)
set(PYTHON_LIBS pybind11::embed)
set(PYTHON_ENGINE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/python-engine.cpp)
if ( ${ZLIB_FOUND} )
message( STATUS "Using System zlib ${ZLIB_VERSION_STRING}" )
@ -292,6 +297,7 @@ set(SRC_CORE
${CMAKE_CURRENT_SOURCE_DIR}/wave.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x6502.cpp
${LUA_ENGINE_SOURCE}
${PYTHON_ENGINE_SOURCE}
${ZLIB_SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/boards/01-222.cpp
${CMAKE_CURRENT_SOURCE_DIR}/boards/09-034a.cpp
@ -632,6 +638,7 @@ target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS}
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
${SYS_LIBS}
${PYTHON_LIBS}
)
if (WIN32)

View File

@ -58,6 +58,8 @@
#include "../../fceulua.h"
#endif
#include "../../fceupython.h"
#include "common/os_utils.h"
#include "common/configSys.h"
#include "../../oldmovie.h"
@ -1068,6 +1070,8 @@ int fceuWrapperInit( int argc, char *argv[] )
{
s = fi.canonicalFilePath().toStdString();
}
FCEU_LoadPythonCode(s.c_str());
}
g_config->getOption("SDL.NewPPU", &newppu);

View File

@ -64,6 +64,8 @@ extern void RefreshThrottleFPS();
#include "fceulua.h"
#endif
#include "fceupython.h"
//TODO - we really need some kind of global platform-specific options api
#ifdef __WIN_DRIVER__
#include "drivers/win/main.h"
@ -796,6 +798,8 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
FCEU_LuaFrameBoundary();
#endif
FCEU_PythonFrameBoundary();
FCEU_UpdateInput();
lagFlag = 1;

7
src/fceupython.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _FCEUPYTHON_H
#define _FCEUPYTHON_H
void FCEU_PythonFrameBoundary();
void FCEU_LoadPythonCode(const char* filename);
#endif //_FCEUPYTHON_H

122
src/python-engine.cpp Normal file
View File

@ -0,0 +1,122 @@
#include <atomic>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <pybind11/embed.h>
namespace py = pybind11;
#include "fceupython.h"
#define SetCurrentDir chdir
// Are we running any code right now?
static char* pythonScriptName = NULL;
bool pythonRunning = false;
// True if there's a thread waiting to run after a run of frame-advance.
static std::atomic_bool frameAdvanceWaiting = false;
// True if there's a thread waiting to run after a run of frame-advance.
static std::atomic_bool inFrameBoundry = false;
std::mutex mtx;
std::condition_variable cv;
// Python thread object
// std::thread python_thread;
void FCEU_PythonFrameBoundary()
{
std::cout << "in FCEU_PythonFrameBoundary" << std::endl;
if(!pythonRunning)
return;
// Notify Python thread the main thread is in the frame boundry
inFrameBoundry = true;
cv.notify_all();
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return bool(frameAdvanceWaiting); });
frameAdvanceWaiting = false;
}
void emu_frameadvance()
{
// Can't call if a frameAdvance is already waiting
if (frameAdvanceWaiting)
return;
frameAdvanceWaiting = true;
// Notify main thread it can advance the frame
cv.notify_all();
// Wait until inFrameBoundry is true to continue python script
std::unique_lock<std::mutex> lock(mtx);
inFrameBoundry = false;
cv.wait(lock, [] { return bool(inFrameBoundry); });
}
PYBIND11_EMBEDDED_MODULE(emu, m)
{
m.def("frameadvance", &emu_frameadvance);
// m.def("framecount", [] { return emu_framecount; });
}
void pythonStart(std::string filename)
{
// Wait until in_frame_boundry is true to start python script
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return bool(inFrameBoundry); });
lock.unlock();
// Start evaluating the python file
py::gil_scoped_acquire acquire;
py::eval_file(filename);
}
/**
* Loads and runs the given Python script.
* The emulator MUST be paused for this function to be
* called. Otherwise, all frame boundary assumptions go out the window.
*
* Returns true on success, false on failure.
*/
void FCEU_LoadPythonCode(const char* filename)
{
if (filename != pythonScriptName)
{
if (pythonScriptName)
free(pythonScriptName);
pythonScriptName = strdup(filename);
}
// Start interpreter
pythonRunning = true;
py::initialize_interpreter();
// gil_scoped_release created on heap to not be destroyed on leaving FCEU_LoadPythonCode scope
py::gil_scoped_release* release = new py::gil_scoped_release;
std::thread(pythonStart, std::string(filename)).detach();
FCEU_PythonFrameBoundary();
}
/**
* Terminates a running Python scripts by killing the whole Python Interpretor.
*/
void FCEU_PythonStop()
{
if (!pythonRunning)
return;
// Stop interpretor
pythonRunning = false;
py::finalize_interpreter();
}