mirror of https://github.com/mgba-emu/mgba.git
Python: Add runner, thread interfaces
This commit is contained in:
parent
e1325b0373
commit
dce49ea990
|
@ -1,5 +1,6 @@
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
#define PNG_H
|
#define PNG_H
|
||||||
|
#define OPAQUE_THREADING
|
||||||
#define _SYS_TIME_H
|
#define _SYS_TIME_H
|
||||||
#define _SYS_TIME_H_
|
#define _SYS_TIME_H_
|
||||||
#define _TIME_H
|
#define _TIME_H
|
||||||
|
@ -30,6 +31,7 @@ void free(void*);
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba/core/mem-search.h>
|
#include <mgba/core/mem-search.h>
|
||||||
#include <mgba/core/tile-cache.h>
|
#include <mgba/core/tile-cache.h>
|
||||||
|
#include <mgba/core/thread.h>
|
||||||
#include <mgba/core/version.h>
|
#include <mgba/core/version.h>
|
||||||
|
|
||||||
#define PYEXPORT extern "Python+C"
|
#define PYEXPORT extern "Python+C"
|
||||||
|
|
|
@ -18,10 +18,12 @@ cppflags.extend(["-I" + incdir, "-I" + srcdir, "-I" + bindir])
|
||||||
|
|
||||||
ffi.set_source("mgba._pylib", """
|
ffi.set_source("mgba._pylib", """
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
|
#define OPAQUE_THREADING
|
||||||
#include <mgba-util/common.h>
|
#include <mgba-util/common.h>
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba/core/log.h>
|
#include <mgba/core/log.h>
|
||||||
#include <mgba/core/mem-search.h>
|
#include <mgba/core/mem-search.h>
|
||||||
|
#include <mgba/core/thread.h>
|
||||||
#include <mgba/core/tile-cache.h>
|
#include <mgba/core/tile-cache.h>
|
||||||
#include <mgba/core/version.h>
|
#include <mgba/core/version.h>
|
||||||
#include <mgba/internal/arm/arm.h>
|
#include <mgba/internal/arm/arm.h>
|
||||||
|
|
|
@ -38,10 +38,18 @@ def needsReset(f):
|
||||||
return f(self, *args, **kwargs)
|
return f(self, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
def protected(f):
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
if self._protected:
|
||||||
|
raise RuntimeError("Core is protected")
|
||||||
|
return f(self, *args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
class Core(object):
|
class Core(object):
|
||||||
def __init__(self, native):
|
def __init__(self, native):
|
||||||
self._core = native
|
self._core = native
|
||||||
self._wasReset = False
|
self._wasReset = False
|
||||||
|
self._protected = False
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def tiles(self):
|
def tiles(self):
|
||||||
|
@ -51,6 +59,7 @@ class Core(object):
|
||||||
def _init(cls, native):
|
def _init(cls, native):
|
||||||
core = ffi.gc(native, native.deinit)
|
core = ffi.gc(native, native.deinit)
|
||||||
success = bool(core.init(core))
|
success = bool(core.init(core))
|
||||||
|
lib.mCoreInitConfig(core, ffi.NULL)
|
||||||
if not success:
|
if not success:
|
||||||
raise RuntimeError("Failed to initialize core")
|
raise RuntimeError("Failed to initialize core")
|
||||||
if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
|
if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA:
|
||||||
|
@ -62,6 +71,7 @@ class Core(object):
|
||||||
def _deinit(self):
|
def _deinit(self):
|
||||||
self._core.deinit(self._core)
|
self._core.deinit(self._core)
|
||||||
|
|
||||||
|
@protected
|
||||||
def loadFile(self, path):
|
def loadFile(self, path):
|
||||||
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
|
return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))
|
||||||
|
|
||||||
|
@ -77,6 +87,7 @@ class Core(object):
|
||||||
def loadTemporarySave(self, vf):
|
def loadTemporarySave(self, vf):
|
||||||
return bool(self._core.loadTemporarySave(self._core, vf.handle))
|
return bool(self._core.loadTemporarySave(self._core, vf.handle))
|
||||||
|
|
||||||
|
@protected
|
||||||
def loadPatch(self, vf):
|
def loadPatch(self, vf):
|
||||||
return bool(self._core.loadPatch(self._core, vf.handle))
|
return bool(self._core.loadPatch(self._core, vf.handle))
|
||||||
|
|
||||||
|
@ -98,19 +109,23 @@ class Core(object):
|
||||||
def setVideoBuffer(self, image):
|
def setVideoBuffer(self, image):
|
||||||
self._core.setVideoBuffer(self._core, image.buffer, image.stride)
|
self._core.setVideoBuffer(self._core, image.buffer, image.stride)
|
||||||
|
|
||||||
|
@protected
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self._core.reset(self._core)
|
self._core.reset(self._core)
|
||||||
self._wasReset = True
|
self._wasReset = True
|
||||||
|
|
||||||
@needsReset
|
@needsReset
|
||||||
|
@protected
|
||||||
def runFrame(self):
|
def runFrame(self):
|
||||||
self._core.runFrame(self._core)
|
self._core.runFrame(self._core)
|
||||||
|
|
||||||
@needsReset
|
@needsReset
|
||||||
|
@protected
|
||||||
def runLoop(self):
|
def runLoop(self):
|
||||||
self._core.runLoop(self._core)
|
self._core.runLoop(self._core)
|
||||||
|
|
||||||
@needsReset
|
@needsReset
|
||||||
|
@protected
|
||||||
def step(self):
|
def step(self):
|
||||||
self._core.step(self._core)
|
self._core.step(self._core)
|
||||||
|
|
||||||
|
@ -152,6 +167,38 @@ class Core(object):
|
||||||
self._core.getGameCode(self._core, code)
|
self._core.getGameCode(self._core, code)
|
||||||
return ffi.string(code, 12).decode("ascii")
|
return ffi.string(code, 12).decode("ascii")
|
||||||
|
|
||||||
|
class ICoreOwner(object):
|
||||||
|
def claim(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def release(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.core = self.claim()
|
||||||
|
self.core._protected = True
|
||||||
|
return self.core
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
self.core._protected = False
|
||||||
|
self.release()
|
||||||
|
|
||||||
|
class IRunner(object):
|
||||||
|
def pause(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def unpause(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def useCore(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def isRunning(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def isPaused(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
if hasattr(lib, 'PLATFORM_GBA'):
|
if hasattr(lib, 'PLATFORM_GBA'):
|
||||||
from .gba import GBA
|
from .gba import GBA
|
||||||
Core.PLATFORM_GBA = lib.PLATFORM_GBA
|
Core.PLATFORM_GBA = lib.PLATFORM_GBA
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Copyright (c) 2013-2017 Jeffrey Pfau
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
from ._pylib import ffi, lib
|
||||||
|
from .core import IRunner, ICoreOwner, Core
|
||||||
|
|
||||||
|
class ThreadCoreOwner(ICoreOwner):
|
||||||
|
def __init__(self, thread):
|
||||||
|
self.thread = thread
|
||||||
|
|
||||||
|
def claim(self):
|
||||||
|
if not self.thread.isRunning():
|
||||||
|
raise ValueError
|
||||||
|
lib.mCoreThreadInterrupt(self.thread._native)
|
||||||
|
return self.thread._core
|
||||||
|
|
||||||
|
def release(self):
|
||||||
|
lib.mCoreThreadContinue(self.thread._native)
|
||||||
|
|
||||||
|
class Thread(IRunner):
|
||||||
|
def __init__(self, native=None):
|
||||||
|
if native:
|
||||||
|
self._native = native
|
||||||
|
self._core = Core(native.core)
|
||||||
|
self._core._wasReset = lib.mCoreThreadHasStarted(self._native)
|
||||||
|
else:
|
||||||
|
self._native = ffi.new("struct mCoreThread*")
|
||||||
|
|
||||||
|
def start(self, core):
|
||||||
|
if lib.mCoreThreadHasStarted(self._native):
|
||||||
|
raise ValueError
|
||||||
|
self._core = core
|
||||||
|
self._native.core = core._core
|
||||||
|
lib.mCoreThreadStart(self._native)
|
||||||
|
self._core._wasReset = lib.mCoreThreadHasStarted(self._native)
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
if not lib.mCoreThreadHasStarted(self._native):
|
||||||
|
raise ValueError
|
||||||
|
lib.mCoreThreadEnd(self._native)
|
||||||
|
lib.mCoreThreadJoin(self._native)
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
lib.mCoreThreadPause(self._native)
|
||||||
|
|
||||||
|
def unpause(self):
|
||||||
|
lib.mCoreThreadUnpause(self._native)
|
||||||
|
|
||||||
|
def isRunning(self):
|
||||||
|
return bool(lib.mCoreThreadIsActive(self._native))
|
||||||
|
|
||||||
|
def isPaused(self):
|
||||||
|
return bool(lib.mCoreThreadIsPaused(self._native))
|
||||||
|
|
||||||
|
def useCore(self):
|
||||||
|
return ThreadCoreOwner(self)
|
Loading…
Reference in New Issue