Merge remote-tracking branch 'origin/rr1-maint'
Conflicts: Makefile src/lua/core.cpp src/lua/lua.cpp
This commit is contained in:
commit
c3dd13fb3f
25 changed files with 577 additions and 49 deletions
2
Makefile
2
Makefile
|
@ -17,7 +17,7 @@ HOSTCC = $(CC)
|
|||
#Flags.
|
||||
HOSTCCFLAGS = -std=gnu++0x
|
||||
CFLAGS = -I$(BSNES_PATH) -std=gnu++0x $(USER_CFLAGS)
|
||||
LDFLAGS = -lboost_iostreams -lboost_filesystem -lboost_system -lboost_regex -lz $(USER_LDFLAGS)
|
||||
LDFLAGS = -lboost_iostreams-mt -lboost_filesystem-mt -lboost_system-mt -lboost_regex-mt -lz $(USER_LDFLAGS)
|
||||
|
||||
#Platform
|
||||
GRAPHICS=SDL
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1-Δ3
|
||||
1-Δ4ε1
|
|
@ -5,6 +5,7 @@
|
|||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
|
|
@ -76,7 +76,7 @@ void init_special_screens() throw(std::bad_alloc);
|
|||
/**
|
||||
* Copy framebuffer to backing store, running Lua hooks if any.
|
||||
*/
|
||||
void redraw_framebuffer(lcscreen& torender, bool no_lua = false);
|
||||
void redraw_framebuffer(lcscreen& torender, bool no_lua = false, bool spontaneous = false);
|
||||
/**
|
||||
* Redraw the framebuffer, reusing contents from last redraw. Runs lua hooks if last redraw ran them.
|
||||
*/
|
||||
|
|
14
include/core/threaddebug.hpp
Normal file
14
include/core/threaddebug.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef _threaddebug__hpp__included__
|
||||
#define _threaddebug__hpp__included__
|
||||
|
||||
#define THREAD_OTHER -1
|
||||
#define THREAD_MAIN -2
|
||||
#define THREAD_EMULATION 0
|
||||
#define THREAD_UI 1
|
||||
#define THREAD_JOYSTICK 2
|
||||
|
||||
void assert_thread(signed shouldbe);
|
||||
void mark_thread_as(signed call_me);
|
||||
void init_threaded_malloc();
|
||||
|
||||
#endif
|
|
@ -14,6 +14,9 @@ bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname);
|
|||
void push_keygroup_parameters(lua_State* LS, const struct keygroup::parameters& p);
|
||||
extern lua_render_context* lua_render_ctx;
|
||||
extern controller_frame* lua_input_controllerdata;
|
||||
extern bool lua_booted_flag;
|
||||
extern uint64_t lua_idle_hook_time;
|
||||
extern uint64_t lua_timer_hook_time;
|
||||
|
||||
template<typename T>
|
||||
T get_numeric_argument(lua_State* LS, unsigned argindex, const char* fname)
|
||||
|
|
|
@ -68,13 +68,17 @@ struct lua_render_context
|
|||
|
||||
void init_lua() throw();
|
||||
void quit_lua() throw();
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx) throw();
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx, bool non_synthethic) throw();
|
||||
void lua_callback_do_video(struct lua_render_context* ctx) throw();
|
||||
void lua_callback_do_input(controller_frame& data, bool subframe) throw();
|
||||
void lua_callback_do_reset() throw();
|
||||
void lua_callback_do_frame() throw();
|
||||
void lua_callback_do_frame_emulated() throw();
|
||||
void lua_callback_do_rewind() throw();
|
||||
void lua_callback_do_readwrite() throw();
|
||||
void lua_callback_startup() throw();
|
||||
void lua_callback_do_idle() throw();
|
||||
void lua_callback_do_timer() throw();
|
||||
void lua_callback_pre_load(const std::string& name) throw();
|
||||
void lua_callback_err_load(const std::string& name) throw();
|
||||
void lua_callback_post_load(const std::string& name, bool was_state) throw();
|
||||
|
@ -85,6 +89,11 @@ void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index
|
|||
void lua_callback_quit() throw();
|
||||
void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw();
|
||||
|
||||
#define LUA_TIMED_HOOK_IDLE 0
|
||||
#define LUA_TIMED_HOOK_TIMER 1
|
||||
|
||||
uint64_t lua_timed_hook(int timer) throw();
|
||||
|
||||
extern bool lua_supported;
|
||||
extern bool lua_requests_repaint;
|
||||
extern bool lua_requests_subframe_paint;
|
||||
|
|
|
@ -11,6 +11,7 @@ public:
|
|||
{
|
||||
public:
|
||||
panel(wxWindow* _parent, unsigned lines);
|
||||
bool AcceptsFocus () const;
|
||||
void on_paint(wxPaintEvent& e);
|
||||
bool dirty;
|
||||
wxWindow* parent;
|
||||
|
|
141
manual.lyx
141
manual.lyx
|
@ -2036,6 +2036,43 @@ exec(string command)
|
|||
Run command as it was entered on the command line
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
utime()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Returns two values.
|
||||
First is time since some epoch in seconds, the second is microseconds mod
|
||||
10^6 since that epoch.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
emulator_ready()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Returns true if emulator has finished booting, false if not (on_startup()
|
||||
will be issued later).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
set_idle_timeout(number timeout)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set number of microseconds to block idle for.
|
||||
After this timeout has expired, on_idle() will be called once.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
set_timer_timeout(number timeout)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set number of microseconds to block timer for.
|
||||
After this timeout has expired, on_timer() will be called once.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
Table bit:
|
||||
\end_layout
|
||||
|
@ -2685,6 +2722,32 @@ Uses physical controller numbering.
|
|||
Gamepad in port 2 is controller 4, not 1!
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.geta(number controller)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Get input state for entiere controller.
|
||||
Returns 13 return values.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
1st return value: Bitmask: bit i is set if i:th index is nonzero
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
2nd-13th return value: value of i:th index.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.seta(number controller, number bitmask, number args...)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Set state for entiere controller.
|
||||
args is up to 12 values for indices (overriding values in bitmask if specified).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
input.reset([number cycles])
|
||||
\end_layout
|
||||
|
@ -3199,7 +3262,7 @@ Various callbacks to Lua that can occur.
|
|||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_paint()
|
||||
Callback: on_paint(bool not_synth)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
|
@ -3207,6 +3270,11 @@ Called when screen is being painted.
|
|||
Any gui.* calls requiring graphic context draw on the screen.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
not_synth is true if this hook is being called in response to received frame,
|
||||
false otherwise.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_video()
|
||||
\end_layout
|
||||
|
@ -3216,6 +3284,15 @@ Called when video dump frame is being painted.
|
|||
Any gui.* calls requiring graphic context draw on the video.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_frame_emulated()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Called when emulating frame has completed and on_paint()/on_video() calls
|
||||
are about to be issued.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_frame()
|
||||
\end_layout
|
||||
|
@ -3232,6 +3309,14 @@ Callback: on_startup()
|
|||
Called when the emulator is starting (lsnes.rc and --run files has been run).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_rewind()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Called when rewind movie to beginning has completed.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_pre_load(string name)
|
||||
\end_layout
|
||||
|
@ -3350,6 +3435,24 @@ Sent when key that has keyhook events requested changes state.
|
|||
table values in input.raw).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_idle()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Called when requested by set_idle_timeout(), the timeout has expired and
|
||||
emulator is waiting.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsubsection
|
||||
Callback: on_timer()
|
||||
\end_layout
|
||||
|
||||
\begin_layout Standard
|
||||
Called when requested by set_idle_timeout() and the timeout has expired
|
||||
(regardless if emulator is waiting).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Section
|
||||
Memory watch expression syntax
|
||||
\end_layout
|
||||
|
@ -5691,5 +5794,41 @@ Wxwidgets: Only bring up ROM patching screen if specifically requested.
|
|||
Allow configuring some hotkeys.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
rr1-delta4
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Lots of code cleanups
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Fix JMD compression (JMD dumping was broken)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Don't crash if Lua C function throws an exception.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Support bitmap drawing in Lua.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Fix bsnes v085/v086 patches.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Improve stability on win32.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
rr1-delta4epsilon1
|
||||
\end_layout
|
||||
|
||||
\begin_layout Itemize
|
||||
Don't corrupt movie if movie length is integer multiple of frames per page.
|
||||
\end_layout
|
||||
|
||||
\end_body
|
||||
\end_document
|
||||
|
|
112
manual.txt
112
manual.txt
|
@ -977,6 +977,26 @@ Print line to message console.
|
|||
|
||||
Run command as it was entered on the command line
|
||||
|
||||
8.1.3 utime()
|
||||
|
||||
Returns two values. First is time since some epoch in seconds,
|
||||
the second is microseconds mod 10^6 since that epoch.
|
||||
|
||||
8.1.4 emulator_ready()
|
||||
|
||||
Returns true if emulator has finished booting, false if not
|
||||
(on_startup() will be issued later).
|
||||
|
||||
8.1.5 set_idle_timeout(number timeout)
|
||||
|
||||
Set number of microseconds to block idle for. After this timeout
|
||||
has expired, on_idle() will be called once.
|
||||
|
||||
8.1.6 set_timer_timeout(number timeout)
|
||||
|
||||
Set number of microseconds to block timer for. After this timeout
|
||||
has expired, on_timer() will be called once.
|
||||
|
||||
8.2 Table bit:
|
||||
|
||||
Bitwise logical functions and related.
|
||||
|
@ -1316,14 +1336,29 @@ storing value. Notes:
|
|||
• Uses physical controller numbering. Gamepad in port 2 is
|
||||
controller 4, not 1!
|
||||
|
||||
8.4.3 input.reset([number cycles])
|
||||
8.4.3 input.geta(number controller)
|
||||
|
||||
Get input state for entiere controller. Returns 13 return values.
|
||||
|
||||
• 1st return value: Bitmask: bit i is set if i:th index is
|
||||
nonzero
|
||||
|
||||
• 2nd-13th return value: value of i:th index.
|
||||
|
||||
8.4.4 input.seta(number controller, number bitmask, number
|
||||
args...)
|
||||
|
||||
Set state for entiere controller. args is up to 12 values for
|
||||
indices (overriding values in bitmask if specified).
|
||||
|
||||
8.4.5 input.reset([number cycles])
|
||||
|
||||
Execute reset. If cycles is greater than zero, do delayed reset.
|
||||
0 (or no value) causes immediate reset.
|
||||
|
||||
• Only available with subframe flag false.
|
||||
|
||||
8.4.4 input.raw()
|
||||
8.4.6 input.raw()
|
||||
|
||||
Returns table of tables of all available keys and axes. The first
|
||||
table is indexed by key name (platform-dependent!), and the inner
|
||||
|
@ -1347,7 +1382,7 @@ table has the following fields:
|
|||
• cal_tolerance: Dead zone tolerance. Only meaningful with axis
|
||||
and pressure types.
|
||||
|
||||
8.4.5 input.keyhook(key, state)
|
||||
8.4.7 input.keyhook(key, state)
|
||||
|
||||
Requests that keyhook events to be sent for key (state=true) or
|
||||
not sent (state=false).
|
||||
|
@ -1602,76 +1637,88 @@ initialization. Non-writeable.
|
|||
|
||||
Various callbacks to Lua that can occur.
|
||||
|
||||
8.10.1 Callback: on_paint()
|
||||
8.10.1 Callback: on_paint(bool not_synth)
|
||||
|
||||
Called when screen is being painted. Any gui.* calls requiring
|
||||
graphic context draw on the screen.
|
||||
|
||||
not_synth is true if this hook is being called in response to
|
||||
received frame, false otherwise.
|
||||
|
||||
8.10.2 Callback: on_video()
|
||||
|
||||
Called when video dump frame is being painted. Any gui.* calls
|
||||
requiring graphic context draw on the video.
|
||||
|
||||
8.10.3 Callback: on_frame()
|
||||
8.10.3 Callback: on_frame_emulated()
|
||||
|
||||
Called when emulating frame has completed and
|
||||
on_paint()/on_video() calls are about to be issued.
|
||||
|
||||
8.10.4 Callback: on_frame()
|
||||
|
||||
Called on each starting whole frame.
|
||||
|
||||
8.10.4 Callback: on_startup()
|
||||
8.10.5 Callback: on_startup()
|
||||
|
||||
Called when the emulator is starting (lsnes.rc and --run files
|
||||
has been run).
|
||||
|
||||
8.10.5 Callback: on_pre_load(string name)
|
||||
8.10.6 Callback: on_rewind()
|
||||
|
||||
Called when rewind movie to beginning has completed.
|
||||
|
||||
8.10.7 Callback: on_pre_load(string name)
|
||||
|
||||
Called just before savestate/movie load occurs (note: loads are
|
||||
always delayed, so this occurs even when load was initiated by
|
||||
lua).
|
||||
|
||||
8.10.6 Callback: on_err_load(string name)
|
||||
8.10.8 Callback: on_err_load(string name)
|
||||
|
||||
Called if loadstate goes wrong.
|
||||
|
||||
8.10.7 Callback: on_post_load(string name, boolean was_savestate)
|
||||
8.10.9 Callback: on_post_load(string name, boolean was_savestate)
|
||||
|
||||
Called on successful loadstate. was_savestate gives if this was a
|
||||
savestate or a movie.
|
||||
|
||||
8.10.8 Callback: on_pre_save(string name, boolean is_savestate)
|
||||
8.10.10 Callback: on_pre_save(string name, boolean is_savestate)
|
||||
|
||||
Called just before savestate save occurs (note: movie saves are
|
||||
synchronous and won't trigger these callbacks if called from
|
||||
Lua).
|
||||
|
||||
8.10.9 Callback: on_err_save(string name)
|
||||
8.10.11 Callback: on_err_save(string name)
|
||||
|
||||
Called if savestate goes wrong.
|
||||
|
||||
8.10.10 Callback: on_post_save(string name, boolean is_savestate)
|
||||
8.10.12 Callback: on_post_save(string name, boolean is_savestate)
|
||||
|
||||
Called on successful savaestate. is_savestate gives if this was a
|
||||
savestate or a movie.
|
||||
|
||||
8.10.11 Callback: on_quit()
|
||||
8.10.13 Callback: on_quit()
|
||||
|
||||
Called when emulator is shutting down.
|
||||
|
||||
8.10.12 Callback: on_input(boolean subframe)
|
||||
8.10.14 Callback: on_input(boolean subframe)
|
||||
|
||||
Called when emulator is just sending input to bsnes core.
|
||||
Warning: This is called even in readonly mode, but the results
|
||||
are ignored.
|
||||
|
||||
8.10.13 Callback: on_reset()
|
||||
8.10.15 Callback: on_reset()
|
||||
|
||||
Called when SNES is reset.
|
||||
|
||||
8.10.14 Callback: on_readwrite()
|
||||
8.10.16 Callback: on_readwrite()
|
||||
|
||||
Called when moving into readwrite mode as result of “set-rwmode”
|
||||
command (note: moving to rwmode by Lua won't trigger this, as per
|
||||
recursive entry protection).
|
||||
|
||||
8.10.15 Callback: on_snoop(number port, number controller, number
|
||||
8.10.17 Callback: on_snoop(number port, number controller, number
|
||||
index, number value)
|
||||
|
||||
Called each time bsnes asks for input. The value is the final
|
||||
|
@ -1680,12 +1727,22 @@ autofire have been taken into account). Might be useful when
|
|||
translating movies to format suitable for console verification.
|
||||
Note: There is no way to modify the value to be sent.
|
||||
|
||||
8.10.16 Callback: on_keyhook(string keyname, table state)
|
||||
8.10.18 Callback: on_keyhook(string keyname, table state)
|
||||
|
||||
Sent when key that has keyhook events requested changes state.
|
||||
Keyname is name of the key (group) and state is the state (same
|
||||
kind as table values in input.raw).
|
||||
|
||||
8.10.19 Callback: on_idle()
|
||||
|
||||
Called when requested by set_idle_timeout(), the timeout has
|
||||
expired and emulator is waiting.
|
||||
|
||||
8.10.20 Callback: on_timer()
|
||||
|
||||
Called when requested by set_idle_timeout() and the timeout has
|
||||
expired (regardless if emulator is waiting).
|
||||
|
||||
9 Memory watch expression syntax
|
||||
|
||||
Memory watch expressions are in RPN (Reverse Polish Notation). At
|
||||
|
@ -2786,3 +2843,22 @@ set-axis joystick0axis19 disabled
|
|||
|
||||
• Allow configuring some hotkeys.
|
||||
|
||||
15.51 rr1-delta4
|
||||
|
||||
• Lots of code cleanups
|
||||
|
||||
• Fix JMD compression (JMD dumping was broken)
|
||||
|
||||
• Don't crash if Lua C function throws an exception.
|
||||
|
||||
• Support bitmap drawing in Lua.
|
||||
|
||||
• Fix bsnes v085/v086 patches.
|
||||
|
||||
• Improve stability on win32.
|
||||
|
||||
15.52 rr1-delta4epsilon1
|
||||
|
||||
• Don't corrupt movie if movie length is integer multiple of
|
||||
frames per page.
|
||||
|
||||
|
|
|
@ -683,8 +683,10 @@ void controller_frame_vector::resize(size_t newsize) throw(std::bad_alloc)
|
|||
for(size_t i = pages_needed; i < current_pages; i++)
|
||||
pages.erase(i);
|
||||
//Now zeroize the excess memory.
|
||||
size_t offset = frame_size * (newsize % frames_per_page);
|
||||
memset(pages[pages_needed - 1].content + offset, 0, CONTROLLER_PAGE_SIZE - offset);
|
||||
if(newsize < pages_needed * frames_per_page) {
|
||||
size_t offset = frame_size * (newsize % frames_per_page);
|
||||
memset(pages[pages_needed - 1].content + offset, 0, CONTROLLER_PAGE_SIZE - offset);
|
||||
}
|
||||
frames = newsize;
|
||||
} else if(newsize > frames) {
|
||||
//Enlarge movie.
|
||||
|
|
|
@ -168,7 +168,7 @@ void init_special_screens() throw(std::bad_alloc)
|
|||
screen_corrupt = lcscreen(&buf[0], 512, 448);
|
||||
}
|
||||
|
||||
void redraw_framebuffer(lcscreen& todraw, bool no_lua)
|
||||
void redraw_framebuffer(lcscreen& todraw, bool no_lua, bool spontaneous)
|
||||
{
|
||||
uint32_t hscl, vscl;
|
||||
auto g = get_scale_factors(todraw.width, todraw.height);
|
||||
|
@ -185,7 +185,7 @@ void redraw_framebuffer(lcscreen& todraw, bool no_lua)
|
|||
lrc.width = todraw.width * hscl;
|
||||
lrc.height = todraw.height * vscl;
|
||||
if(!no_lua)
|
||||
lua_callback_do_paint(&lrc);
|
||||
lua_callback_do_paint(&lrc, spontaneous);
|
||||
ri.fbuf = todraw;
|
||||
ri.hscl = hscl;
|
||||
ri.vscl = vscl;
|
||||
|
@ -203,7 +203,8 @@ void redraw_framebuffer()
|
|||
render_info& ri = get_read_buffer();
|
||||
lcscreen copy = ri.fbuf;
|
||||
buffering.end_read();
|
||||
redraw_framebuffer(copy, last_redraw_no_lua);
|
||||
//Redraws are never spontaneous
|
||||
redraw_framebuffer(copy, last_redraw_no_lua, false);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -335,6 +335,7 @@ class my_interface : public SNES::Interface
|
|||
if(stepping_into_save)
|
||||
messages << "Got video refresh in runtosave, expect desyncs!" << std::endl;
|
||||
video_refresh_done = true;
|
||||
lua_callback_do_frame_emulated();
|
||||
bool region = (SNES::system.region() == SNES::System::Region::PAL);
|
||||
information_dispatch::do_raw_frame(data, hires, interlace, overscan, region ? VIDEO_REGION_PAL :
|
||||
VIDEO_REGION_NTSC);
|
||||
|
@ -345,7 +346,7 @@ class my_interface : public SNES::Interface
|
|||
lcscreen ls(data, hires, interlace, overscan, region);
|
||||
location_special = SPECIAL_FRAME_VIDEO;
|
||||
update_movie_state();
|
||||
redraw_framebuffer(ls);
|
||||
redraw_framebuffer(ls, false, true);
|
||||
uint32_t fps_n, fps_d;
|
||||
uint32_t fclocks;
|
||||
if(region)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "core/memorymanip.hpp"
|
||||
#include "core/misc.hpp"
|
||||
#include "core/rom.hpp"
|
||||
#include "core/threaddebug.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
|
||||
|
@ -248,6 +249,7 @@ bool in_global_ctors()
|
|||
void reached_main()
|
||||
{
|
||||
reached_main_flag = true;
|
||||
init_threaded_malloc();
|
||||
}
|
||||
|
||||
std::string bsnes_core_version;
|
||||
|
|
|
@ -470,14 +470,15 @@ long movie_logic::new_frame_starting(bool dont_poll) throw(std::bad_alloc, std::
|
|||
controller_frame c = update_controls(false);
|
||||
if(!mov.readonly_mode()) {
|
||||
mov.set_controls(c);
|
||||
if(dont_poll)
|
||||
if(!dont_poll)
|
||||
mov.set_all_DRDY();
|
||||
if(c.reset()) {
|
||||
auto g = c.delay();
|
||||
long hi = g.first, lo = g.second;
|
||||
mov.commit_reset(hi * 10000 + lo);
|
||||
}
|
||||
}
|
||||
} else if(!dont_poll)
|
||||
mov.set_all_DRDY();
|
||||
return mov.get_reset_status();
|
||||
}
|
||||
|
||||
|
|
|
@ -277,6 +277,7 @@ void do_load_beginning() throw(std::bad_alloc, std::runtime_error)
|
|||
our_movie.rtc_second = our_movie.movie_rtc_second;
|
||||
our_movie.rtc_subsecond = our_movie.movie_rtc_subsecond;
|
||||
redraw_framebuffer(screen_nosignal);
|
||||
lua_callback_do_rewind();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
|
|
91
src/core/threaddebug.cpp
Normal file
91
src/core/threaddebug.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include "core/threaddebug.hpp"
|
||||
#include "core/window.hpp"
|
||||
|
||||
#define DESIGNATED_THREADS 16
|
||||
|
||||
namespace
|
||||
{
|
||||
volatile thread_id* threads[DESIGNATED_THREADS];
|
||||
volatile bool thread_marked;
|
||||
mutex* malloc_mutex;
|
||||
}
|
||||
|
||||
void assert_thread(signed shouldbe, const std::string& desc)
|
||||
{
|
||||
#ifndef DISABLE_THREAD_ASSERTIONS
|
||||
if(shouldbe < 0 || shouldbe >= DESIGNATED_THREADS) {
|
||||
std::cerr << "WARNING: assert_thread(" << shouldbe << ") called." << std::endl;
|
||||
return;
|
||||
}
|
||||
if(!thread_marked)
|
||||
return;
|
||||
thread_id* t = const_cast<thread_id*>(threads[shouldbe]);
|
||||
if(!t || !t->is_me())
|
||||
std::cerr << "WARNING: " << desc << ": Wrong thread!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mark_thread_as(signed call_me)
|
||||
{
|
||||
#ifndef DISABLE_THREAD_ASSERTIONS
|
||||
if(call_me < 0 || call_me >= DESIGNATED_THREADS) {
|
||||
std::cerr << "WARNING: mark_thread_as(" << call_me << ") called." << std::endl;
|
||||
return;
|
||||
}
|
||||
thread_marked = true;
|
||||
threads[call_me] = &thread_id::me();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MAKE_MALLOC_THREADSAFE
|
||||
void init_threaded_malloc()
|
||||
{
|
||||
if(!malloc_mutex)
|
||||
malloc_mutex = &mutex::aquire();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void* __real_malloc(size_t);
|
||||
void* __real_calloc(size_t, size_t);
|
||||
void* __real_realloc(void*, size_t);
|
||||
void __real_free(void*);
|
||||
|
||||
void* __wrap_malloc(size_t block)
|
||||
{
|
||||
if(!malloc_mutex)
|
||||
return __real_malloc(block);
|
||||
mutex::holder(*malloc_mutex);
|
||||
return __real_malloc(block);
|
||||
}
|
||||
|
||||
void* __wrap_calloc(size_t count, size_t size)
|
||||
{
|
||||
if(!malloc_mutex)
|
||||
return __real_calloc(count, size);
|
||||
mutex::holder(*malloc_mutex);
|
||||
return __real_calloc(count, size);
|
||||
}
|
||||
|
||||
void* __wrap_realloc(void* block, size_t size)
|
||||
{
|
||||
if(!malloc_mutex)
|
||||
return __real_realloc(block, size);
|
||||
mutex::holder(*malloc_mutex);
|
||||
return __real_realloc(block, size);
|
||||
}
|
||||
|
||||
void __wrap_free(void* block)
|
||||
{
|
||||
if(!malloc_mutex)
|
||||
return __real_free(block);
|
||||
mutex::holder(*malloc_mutex);
|
||||
return __real_free(block);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void init_threaded_malloc()
|
||||
{
|
||||
}
|
||||
#endif
|
|
@ -1,10 +1,12 @@
|
|||
#include "core/command.hpp"
|
||||
#include "core/dispatch.hpp"
|
||||
#include "core/framerate.hpp"
|
||||
#include "lua/lua.hpp"
|
||||
#include "core/misc.hpp"
|
||||
#include "core/render.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -118,6 +120,8 @@ keypress::keypress(modifier_set mod, keygroup& _key, keygroup& _key2, short _val
|
|||
|
||||
namespace
|
||||
{
|
||||
bool queue_function_run = false;
|
||||
|
||||
function_ptr_command<> identify_key("show-plugins", "Show plugins in use",
|
||||
"Syntax: show-plugins\nShows plugins in use.\n",
|
||||
[]() throw(std::bad_alloc, std::runtime_error) {
|
||||
|
@ -381,6 +385,7 @@ namespace
|
|||
if(k.key2)
|
||||
k.key2->set_position(k.value, k.modifiers);
|
||||
queue_lock->lock();
|
||||
queue_function_run = true;
|
||||
}
|
||||
//Flush commands.
|
||||
while(!commands.empty()) {
|
||||
|
@ -389,6 +394,7 @@ namespace
|
|||
queue_lock->unlock();
|
||||
command::invokeC(c);
|
||||
queue_lock->lock();
|
||||
queue_function_run = true;
|
||||
}
|
||||
//Flush functions.
|
||||
while(!functions.empty()) {
|
||||
|
@ -398,6 +404,7 @@ namespace
|
|||
f.first(f.second);
|
||||
queue_lock->lock();
|
||||
++functions_executed;
|
||||
queue_function_run = true;
|
||||
}
|
||||
queue_condition->signal();
|
||||
} catch(std::bad_alloc& e) {
|
||||
|
@ -409,28 +416,62 @@ namespace
|
|||
if(!unlocked)
|
||||
queue_lock->unlock();
|
||||
}
|
||||
|
||||
uint64_t on_idle_time;
|
||||
uint64_t on_timer_time;
|
||||
void reload_lua_timers()
|
||||
{
|
||||
on_idle_time = lua_timed_hook(LUA_TIMED_HOOK_IDLE);
|
||||
on_timer_time = lua_timed_hook(LUA_TIMED_HOOK_TIMER);
|
||||
queue_function_run = false;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXWAIT 10000
|
||||
#define MAXWAIT 5000000ULL
|
||||
|
||||
|
||||
void platform::flush_command_queue() throw()
|
||||
{
|
||||
reload_lua_timers();
|
||||
queue_function_run = false;
|
||||
if(modal_pause || normal_pause)
|
||||
freeze_time(get_utime());
|
||||
init_threading();
|
||||
bool run_idle = false;
|
||||
while(true) {
|
||||
uint64_t now = get_utime();
|
||||
if(now >= on_timer_time) {
|
||||
lua_callback_do_timer();
|
||||
reload_lua_timers();
|
||||
}
|
||||
if(run_idle) {
|
||||
lua_callback_do_idle();
|
||||
reload_lua_timers();
|
||||
run_idle = false;
|
||||
}
|
||||
mutex::holder h(*queue_lock);
|
||||
internal_run_queues(true);
|
||||
if(!pausing_allowed)
|
||||
break;
|
||||
uint64_t now = get_utime();
|
||||
if(queue_function_run)
|
||||
reload_lua_timers();
|
||||
now = get_utime();
|
||||
uint64_t waitleft = 0;
|
||||
waitleft = (now < continue_time) ? (continue_time - now) : 0;
|
||||
waitleft = (modal_pause || normal_pause) ? MAXWAIT : waitleft;
|
||||
waitleft = (waitleft > MAXWAIT) ? MAXWAIT : waitleft;
|
||||
if(waitleft > 0)
|
||||
queue_condition->wait(waitleft);
|
||||
else
|
||||
waitleft = min(waitleft, static_cast<uint64_t>(MAXWAIT));
|
||||
if(waitleft > 0) {
|
||||
if(now >= on_idle_time) {
|
||||
run_idle = true;
|
||||
waitleft = 0;
|
||||
}
|
||||
if(on_idle_time >= now)
|
||||
waitleft = min(waitleft, on_idle_time - now);
|
||||
if(on_timer_time >= now)
|
||||
waitleft = min(waitleft, on_timer_time - now);
|
||||
if(waitleft > 0)
|
||||
queue_condition->wait(waitleft);
|
||||
} else
|
||||
break;
|
||||
//If we had to wait, check queues at least once more.
|
||||
}
|
||||
|
@ -445,18 +486,41 @@ void platform::set_paused(bool enable) throw()
|
|||
|
||||
void platform::wait(uint64_t usec) throw()
|
||||
{
|
||||
reload_lua_timers();
|
||||
continue_time = get_utime() + usec;
|
||||
init_threading();
|
||||
bool run_idle = false;
|
||||
while(true) {
|
||||
uint64_t now = get_utime();
|
||||
if(now >= on_timer_time) {
|
||||
lua_callback_do_timer();
|
||||
reload_lua_timers();
|
||||
}
|
||||
if(run_idle) {
|
||||
lua_callback_do_idle();
|
||||
run_idle = false;
|
||||
reload_lua_timers();
|
||||
}
|
||||
mutex::holder h(*queue_lock);
|
||||
internal_run_queues(true);
|
||||
uint64_t now = get_utime();
|
||||
if(queue_function_run)
|
||||
reload_lua_timers();
|
||||
now = get_utime();
|
||||
uint64_t waitleft = 0;
|
||||
waitleft = (now < continue_time) ? (continue_time - now) : 0;
|
||||
waitleft = (waitleft > MAXWAIT) ? MAXWAIT : waitleft;
|
||||
if(waitleft > 0)
|
||||
queue_condition->wait(waitleft);
|
||||
else
|
||||
waitleft = min(static_cast<uint64_t>(MAXWAIT), waitleft);
|
||||
if(waitleft > 0) {
|
||||
if(now >= on_idle_time) {
|
||||
run_idle = true;
|
||||
waitleft = 0;
|
||||
}
|
||||
if(on_idle_time >= now)
|
||||
waitleft = min(waitleft, on_idle_time - now);
|
||||
if(on_timer_time >= now)
|
||||
waitleft = min(waitleft, on_timer_time - now);
|
||||
if(waitleft > 0)
|
||||
queue_condition->wait(waitleft);
|
||||
} else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "core/command.hpp"
|
||||
#include "lua/internal.hpp"
|
||||
#include "core/framerate.hpp"
|
||||
#include "core/window.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -45,4 +46,27 @@ namespace
|
|||
command::invokeC(text);
|
||||
return 0;
|
||||
});
|
||||
|
||||
function_ptr_luafun lua_booted("emulator_ready", [](lua_State* LS, const std::string& fname) -> int {
|
||||
lua_pushboolean(LS, lua_booted_flag ? 1 : 0);
|
||||
return 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun lua_utime("utime", [](lua_State* LS, const std::string& fname) -> int {
|
||||
uint64_t t = get_utime();
|
||||
lua_pushnumber(LS, t / 1000000);
|
||||
lua_pushnumber(LS, t % 1000000);
|
||||
return 2;
|
||||
});
|
||||
|
||||
function_ptr_luafun lua_idle_time("set_idle_timeout", [](lua_State* LS, const std::string& fname) -> int {
|
||||
lua_idle_hook_time = get_utime() + get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
|
||||
return 0;
|
||||
});
|
||||
|
||||
function_ptr_luafun lua_timer_time("set_timer_timeout", [](lua_State* LS, const std::string& fname) -> int {
|
||||
lua_timer_hook_time = get_utime() + get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
|
||||
return 0;
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
struct lua_State { int x; };
|
||||
lua_function::lua_function(const std::string& name) throw(std::bad_alloc) {}
|
||||
lua_function::~lua_function() throw() {}
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx) throw() {}
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx, bool nonsynth) throw() {}
|
||||
void lua_callback_do_video(struct lua_render_context* ctx) throw() {}
|
||||
void lua_callback_do_input(controller_frame& data, bool subframe) throw() {}
|
||||
void lua_callback_do_reset() throw() {}
|
||||
void lua_callback_do_frame() throw() {}
|
||||
void lua_callback_do_frame_emulated() throw() {}
|
||||
void lua_callback_do_rewind() throw() {}
|
||||
void lua_callback_do_idle() throw() {}
|
||||
void lua_callback_do_timer() throw() {}
|
||||
void lua_callback_do_readwrite() throw() {}
|
||||
void lua_callback_startup() throw() {}
|
||||
void lua_callback_pre_load(const std::string& name) throw() {}
|
||||
|
@ -22,9 +26,14 @@ void lua_callback_quit() throw() {}
|
|||
void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw() {}
|
||||
void init_lua() throw() {}
|
||||
void quit_lua() throw() {}
|
||||
uint64_t lua_timed_hook(int timer) throw() { return 0x7EFFFFFFFFFFFFFFULL; }
|
||||
|
||||
bool lua_requests_repaint = false;
|
||||
bool lua_requests_subframe_paint = false;
|
||||
bool lua_supported = false;
|
||||
uint64_t lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
uint64_t lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
|
||||
#endif
|
||||
|
||||
char SYMBOL_3263572374236473826587375832743243264346;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "core/lua-int.hpp"
|
||||
#include "lua/internal.hpp"
|
||||
#include "core/render.hpp"
|
||||
#include "lua/bitmap.hpp"
|
||||
#include <vector>
|
||||
|
@ -48,7 +48,7 @@ namespace
|
|||
delete p;
|
||||
}
|
||||
|
||||
void operator()(struct screen& scr) throw()
|
||||
template<bool T> void composite_op(struct screen<T>& scr) throw()
|
||||
{
|
||||
size_t pallim = 0;
|
||||
size_t w, h;
|
||||
|
@ -74,7 +74,7 @@ namespace
|
|||
clip_range(scr.originx, scr.width, x, xmin, xmax);
|
||||
clip_range(scr.originy, scr.height, y, ymin, ymax);
|
||||
for(int32_t r = ymin; r < ymax; r++) {
|
||||
uint32_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
typename screen<T>::element_t* rptr = scr.rowptr(y + r + scr.originy);
|
||||
size_t eptr = x + xmin + scr.originx;
|
||||
if(b)
|
||||
for(int32_t c = xmin; c < xmax; c++, eptr++) {
|
||||
|
@ -87,6 +87,8 @@ namespace
|
|||
b2->object()->pixels[r * b2->object()->width + c].apply(rptr[eptr]);
|
||||
}
|
||||
}
|
||||
void operator()(struct screen<false>& x) throw() { composite_op(x); }
|
||||
void operator()(struct screen<true>& x) throw() { composite_op(x); }
|
||||
private:
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
|
|
@ -26,6 +26,38 @@ namespace
|
|||
return 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun iseta("input.seta", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
short val;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT)
|
||||
return 0;
|
||||
uint64_t base = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++) {
|
||||
val = (base >> i) & 1;
|
||||
get_numeric_argument<short>(LS, i + 3, val, fname.c_str());
|
||||
lua_input_controllerdata->axis(controller, i, val);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
function_ptr_luafun igeta("input.geta", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT)
|
||||
return 0;
|
||||
uint64_t fret = 0;
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++)
|
||||
if(lua_input_controllerdata->axis(controller, i))
|
||||
fret |= (1ULL << i);
|
||||
lua_pushnumber(LS, fret);
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++)
|
||||
lua_pushnumber(LS, lua_input_controllerdata->axis(controller, i));
|
||||
return MAX_CONTROLS_PER_CONTROLLER + 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun ireset("input.reset", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
|
|
|
@ -15,6 +15,9 @@ extern "C" {
|
|||
#include <lualib.h>
|
||||
}
|
||||
|
||||
uint64_t lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
uint64_t lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
|
||||
namespace
|
||||
{
|
||||
globalwrap<std::map<std::string, lua_function*>> functions;
|
||||
|
@ -166,6 +169,7 @@ void push_keygroup_parameters(lua_State* LS, const struct keygroup::parameters&
|
|||
|
||||
lua_render_context* lua_render_ctx = NULL;
|
||||
controller_frame* lua_input_controllerdata = NULL;
|
||||
bool lua_booted_flag = false;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -334,12 +338,13 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx) throw()
|
||||
void lua_callback_do_paint(struct lua_render_context* ctx, bool non_synthetic) throw()
|
||||
{
|
||||
if(!callback_exists("on_paint"))
|
||||
return;
|
||||
lua_render_ctx = ctx;
|
||||
run_lua_cb(0);
|
||||
push_boolean(non_synthetic);
|
||||
run_lua_cb(1);
|
||||
lua_render_ctx = NULL;
|
||||
}
|
||||
|
||||
|
@ -366,6 +371,36 @@ void lua_callback_do_frame() throw()
|
|||
run_lua_cb(0);
|
||||
}
|
||||
|
||||
void lua_callback_do_rewind() throw()
|
||||
{
|
||||
if(!callback_exists("on_rewind"))
|
||||
return;
|
||||
run_lua_cb(0);
|
||||
}
|
||||
|
||||
void lua_callback_do_idle() throw()
|
||||
{
|
||||
lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
if(!callback_exists("on_idle"))
|
||||
return;
|
||||
run_lua_cb(0);
|
||||
}
|
||||
|
||||
void lua_callback_do_timer() throw()
|
||||
{
|
||||
lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
|
||||
if(!callback_exists("on_timer"))
|
||||
return;
|
||||
run_lua_cb(0);
|
||||
}
|
||||
|
||||
void lua_callback_do_frame_emulated() throw()
|
||||
{
|
||||
if(!callback_exists("on_frame_emulated"))
|
||||
return;
|
||||
run_lua_cb(0);
|
||||
}
|
||||
|
||||
void lua_callback_do_readwrite() throw()
|
||||
{
|
||||
if(!callback_exists("on_readwrite"))
|
||||
|
@ -375,6 +410,7 @@ void lua_callback_do_readwrite() throw()
|
|||
|
||||
void lua_callback_startup() throw()
|
||||
{
|
||||
lua_booted_flag = true;
|
||||
if(!callback_exists("on_startup"))
|
||||
return;
|
||||
run_lua_cb(0);
|
||||
|
@ -505,6 +541,21 @@ void quit_lua() throw()
|
|||
lua_close(lua_initialized);
|
||||
}
|
||||
|
||||
|
||||
#define LUA_TIMED_HOOK_IDLE 0
|
||||
#define LUA_TIMED_HOOK_TIMER 1
|
||||
|
||||
uint64_t lua_timed_hook(int timer) throw()
|
||||
{
|
||||
switch(timer) {
|
||||
case LUA_TIMED_HOOK_IDLE:
|
||||
return lua_idle_hook_time;
|
||||
case LUA_TIMED_HOOK_TIMER:
|
||||
return lua_timer_hook_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool lua_requests_repaint = false;
|
||||
bool lua_requests_subframe_paint = false;
|
||||
bool lua_supported = true;
|
||||
|
|
|
@ -289,7 +289,7 @@ void handle_wx_keyboard(wxKeyEvent& e, bool polarity)
|
|||
modifier_set mset;
|
||||
modifier_entry* m = modifiers;
|
||||
while(m->name) {
|
||||
if((keyc & m->mod) == m->mod) {
|
||||
if((mods & m->mod) == m->mod) {
|
||||
mset.add(*m->allocated);
|
||||
}
|
||||
m++;
|
||||
|
|
|
@ -15,6 +15,10 @@ wxwin_status::panel::panel(wxWindow* _parent, unsigned lines)
|
|||
this->Connect(wxEVT_PAINT, wxPaintEventHandler(wxwin_status::panel::on_paint), NULL, this);
|
||||
}
|
||||
|
||||
bool wxwin_status::panel::AcceptsFocus () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wxwin_status::wxwin_status()
|
||||
: wxFrame(NULL, wxID_ANY, wxT("lsnes: Status"), wxDefaultPosition, wxSize(-1, -1),
|
||||
|
|
Loading…
Add table
Reference in a new issue