mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-08-23 15:23:44 +02:00
Fix frame duping bugs in libretro builds
* Fixed a bug where frames are still duped when the frontend is fast-forwarding * Fixed a bug where manual frame duping (without `RETRO_ENVIRONMENT_GET_CAN_DUPE`) causes screen flickering during a `Graphics.transition` call
This commit is contained in:
parent
5c14f2352e
commit
2b3a97e83c
6 changed files with 48 additions and 14 deletions
|
@ -65,6 +65,8 @@ namespace mkxp_sandbox {
|
|||
duration = 8;
|
||||
vague = 40;
|
||||
|
||||
sb().transitioning = true;
|
||||
|
||||
if (!shState->graphics().frozen()) {
|
||||
return SANDBOX_NIL;
|
||||
}
|
||||
|
@ -92,6 +94,8 @@ namespace mkxp_sandbox {
|
|||
}
|
||||
|
||||
~coro() {
|
||||
sb().transitioning = false;
|
||||
|
||||
if (trans_map != NULL) {
|
||||
delete trans_map;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ void sandbox::sandbox_free(usize ptr) {
|
|||
w2c_ruby_mkxp_sandbox_free(RB, ptr);
|
||||
}
|
||||
|
||||
sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings(ruby), yielding(false) {
|
||||
sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings(ruby), yielding(false), transitioning(false) {
|
||||
try {
|
||||
// Initialize the sandbox
|
||||
wasm2c_ruby_instantiate(RB, wasi.get());
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace mkxp_sandbox {
|
|||
void sandbox_free(usize ptr);
|
||||
|
||||
public:
|
||||
bool transitioning;
|
||||
inline struct mkxp_sandbox::bindings &operator*() noexcept { return *bindings; }
|
||||
inline struct mkxp_sandbox::bindings *operator->() noexcept { return &*bindings; }
|
||||
sandbox();
|
||||
|
|
33
src/core.cpp
33
src/core.cpp
|
@ -69,6 +69,7 @@ struct lock_guard {
|
|||
};
|
||||
|
||||
static uint64_t frame_count;
|
||||
static uint64_t frame_time;
|
||||
static uint64_t retro_run_count;
|
||||
|
||||
extern const uint8_t mkxp_retro_dist_zip[];
|
||||
|
@ -85,12 +86,15 @@ static bool dupe_supported;
|
|||
static PHYSFS_File *rgssad = NULL;
|
||||
static retro_system_av_info av_info;
|
||||
static struct retro_audio_callback audio_callback;
|
||||
static struct retro_frame_time_callback frame_time_callback;
|
||||
static struct retro_frame_time_callback frame_time_callback = {
|
||||
.callback = [](retro_usec_t delta) {
|
||||
frame_time += delta;
|
||||
},
|
||||
};
|
||||
static std::mutex threaded_audio_mutex;
|
||||
static bool threaded_audio_enabled = false;
|
||||
static bool frame_time_callback_enabled = false;
|
||||
static std::atomic<bool> shared_state_initialized(false);
|
||||
static uint64_t frame_time;
|
||||
|
||||
namespace mkxp_retro {
|
||||
retro_log_printf_t log_printf;
|
||||
|
@ -337,15 +341,16 @@ static bool init_sandbox() {
|
|||
av_info.geometry.aspect_ratio = (float)av_info.geometry.base_width / (float)av_info.geometry.base_height;
|
||||
av_info.timing.sample_rate = (double)SYNTH_SAMPLERATE;
|
||||
frame_time_callback.reference = 1000000 / (rgssVer == 1 ? 40 : 60);
|
||||
frame_time_callback_enabled = environment(RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, &frame_time_callback);
|
||||
|
||||
sound_buf = (int16_t *)mkxp_aligned_malloc(16, (threaded_audio_enabled ? THREADED_AUDIO_SAMPLES : (size_t)std::ceil((double)SYNTH_SAMPLERATE / av_info.timing.fps)) * 2 * sizeof(int16_t));
|
||||
if (sound_buf == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
retro_run_count = 0;
|
||||
frame_count = 0;
|
||||
frame_time = 0;
|
||||
retro_run_count = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -435,7 +440,7 @@ extern "C" RETRO_API void retro_reset() {
|
|||
}
|
||||
|
||||
extern "C" RETRO_API void retro_run() {
|
||||
bool should_render = mkxp_retro::sandbox.has_value() && (!frame_time_callback_enabled || frame_time >= frame_time_callback.reference);
|
||||
bool should_render = mkxp_retro::sandbox.has_value() && (frame_count == 0 || frame_time >= frame_time_callback.reference);
|
||||
|
||||
input_poll();
|
||||
|
||||
|
@ -443,7 +448,7 @@ extern "C" RETRO_API void retro_run() {
|
|||
if (!shared_state_initialized.load(std::memory_order_relaxed)) {
|
||||
SharedState::initInstance(&thread_data.get());
|
||||
shared_state_initialized.store(true, std::memory_order_seq_cst);
|
||||
} else if (hw_render.context_type != RETRO_HW_CONTEXT_NONE) {
|
||||
} else if (hw_render.context_type != RETRO_HW_CONTEXT_NONE && (should_render || (!dupe_supported && mkxp_retro::sandbox.has_value()))) {
|
||||
glState.reset();
|
||||
}
|
||||
|
||||
|
@ -458,7 +463,7 @@ extern "C" RETRO_API void retro_run() {
|
|||
deinit_sandbox();
|
||||
}
|
||||
} else if (!dupe_supported && mkxp_retro::sandbox.has_value()) {
|
||||
shState->graphics().wait(1);
|
||||
shState->graphics().repaint(sb().transitioning);
|
||||
}
|
||||
|
||||
void *fb;
|
||||
|
@ -501,7 +506,15 @@ extern "C" RETRO_API void retro_run() {
|
|||
++retro_run_count;
|
||||
|
||||
if (mkxp_retro::sandbox.has_value()) {
|
||||
frame_time_callback.reference = 1000000 / shState->graphics().getFrameRate();
|
||||
retro_usec_t new_reference = 1000000 / shState->graphics().getFrameRate();
|
||||
if (new_reference != frame_time_callback.reference) {
|
||||
frame_time_callback.reference = new_reference;
|
||||
frame_time_callback_enabled = environment(RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, &frame_time_callback);
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame_time_callback_enabled) {
|
||||
frame_time += frame_time_callback.reference;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,12 +595,6 @@ extern "C" RETRO_API bool retro_load_game(const struct retro_game_info *info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
frame_time_callback.callback = [](retro_usec_t delta) {
|
||||
frame_time += delta;
|
||||
};
|
||||
frame_time_callback.reference = 1000000 / 60;
|
||||
frame_time_callback_enabled = environment(RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK, &frame_time_callback);
|
||||
|
||||
#ifdef MKXPZ_HAVE_THREADED_AUDIO
|
||||
audio_callback.callback = []() {
|
||||
if (!shared_state_initialized.load(std::memory_order_seq_cst)) {
|
||||
|
|
|
@ -1862,6 +1862,27 @@ void Graphics::setFrameskip(bool value) { p->useFrameSkip = value; }
|
|||
|
||||
Scene *Graphics::getScreen() const { return &p->screen; }
|
||||
|
||||
void Graphics::repaint(bool useBackBuffer) {
|
||||
/* Repaint the screen with the last good frame we drew */
|
||||
TEXFBO &lastFrame = useBackBuffer ? p->screen.getPP().backBuffer() : p->screen.getPP().frontBuffer();
|
||||
|
||||
int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), lastFrame, IntRect(0, 0, p->scRes.x, p->scRes.y));
|
||||
|
||||
GLMeta::blitBeginScreen(p->winSize, scaleIsSpecial);
|
||||
GLMeta::blitSource(lastFrame, scaleIsSpecial);
|
||||
|
||||
FBO::clear();
|
||||
p->metaBlitBufferFlippedScaled(scaleIsSpecial);
|
||||
#ifndef MKXPZ_RETRO
|
||||
SDL_GL_SwapWindow(p->threadData->window);
|
||||
p->fpsLimiter.delay();
|
||||
|
||||
p->threadData->ethread->notifyFrame();
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
GLMeta::blitEnd();
|
||||
}
|
||||
|
||||
void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset) {
|
||||
if (exitCond)
|
||||
return;
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
|
||||
/* <internal> */
|
||||
Scene *getScreen() const;
|
||||
void repaint(bool useBackBuffer = false);
|
||||
/* Repaint screen with static image until exitCond
|
||||
* is set. Observes reset flag on top of shutdown
|
||||
* if "checkReset" */
|
||||
|
|
Loading…
Add table
Reference in a new issue