mGUI: Cache save state screenshot validity in state menu (fixes #2005)

This commit is contained in:
Vicki Pfau 2021-06-23 18:53:06 -07:00
parent ccafcf7bdc
commit c6aa7c6673
3 changed files with 52 additions and 36 deletions

View File

@ -23,6 +23,7 @@ Other fixes:
- GB Audio: Fix audio channel 4 being slow to deserialize - GB Audio: Fix audio channel 4 being slow to deserialize
- GB Core: Fix GBC colors setting breaking default model overrides (fixes mgba.io/i/2161) - GB Core: Fix GBC colors setting breaking default model overrides (fixes mgba.io/i/2161)
- GBA: Fix out of bounds ROM accesses on patched ROMs smaller than 32 MiB - GBA: Fix out of bounds ROM accesses on patched ROMs smaller than 32 MiB
- mGUI: Cache save state screenshot validity in state menu (fixes mgba.io/i/2005)
- Qt: Fix infrequent deadlock when using sync to video - Qt: Fix infrequent deadlock when using sync to video
- Qt: Fix applying savetype-only overrides - Qt: Fix applying savetype-only overrides
- Qt: Fix crash in sprite view for partially out-of-bounds sprites (fixes mgba.io/i/2165) - Qt: Fix crash in sprite view for partially out-of-bounds sprites (fixes mgba.io/i/2165)

View File

@ -42,6 +42,11 @@ enum {
#define RUNNER_STATE(X) ((X) << 16) #define RUNNER_STATE(X) ((X) << 16)
enum {
SCREENSHOT_VALID = 0x10000,
SCREENSHOT_INVALID = 0x20000,
};
static const struct mInputPlatformInfo _mGUIKeyInfo = { static const struct mInputPlatformInfo _mGUIKeyInfo = {
.platformName = "gui", .platformName = "gui",
.keyId = (const char*[GUI_INPUT_MAX]) { .keyId = (const char*[GUI_INPUT_MAX]) {
@ -107,39 +112,49 @@ static void _drawBackground(struct GUIBackground* background, void* context) {
static void _drawState(struct GUIBackground* background, void* id) { static void _drawState(struct GUIBackground* background, void* id) {
struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background; struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background;
int stateId = ((int) id) >> 16; unsigned stateId = ((uint32_t) id) >> 16;
if (gbaBackground->p->drawScreenshot) { if (gbaBackground->p->drawScreenshot) {
unsigned w, h; unsigned w, h;
gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h); gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h);
if (gbaBackground->screenshot && gbaBackground->screenshotId == (int) id) { size_t size = w * h * BYTES_PER_PIXEL;
gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->screenshot, w, h, true); if (size != gbaBackground->imageSize) {
mappedMemoryFree(gbaBackground->image, gbaBackground->imageSize);
gbaBackground->image = NULL;
}
if (gbaBackground->image && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) {
gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->image, w, h, true);
return; return;
} } else if (gbaBackground->screenshotId != (stateId | SCREENSHOT_INVALID)) {
struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false); struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false);
color_t* pixels = gbaBackground->screenshot; color_t* pixels = gbaBackground->image;
if (!pixels) { if (!pixels) {
pixels = anonymousMemoryMap(w * h * 4); pixels = anonymousMemoryMap(size);
gbaBackground->screenshot = pixels; gbaBackground->image = pixels;
} gbaBackground->imageSize = size;
bool success = false; }
if (vf && isPNG(vf) && pixels) { bool success = false;
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES); if (vf && isPNG(vf) && pixels) {
png_infop info = png_create_info_struct(png); png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
png_infop end = png_create_info_struct(png); png_infop info = png_create_info_struct(png);
if (png && info && end) { png_infop end = png_create_info_struct(png);
success = PNGReadHeader(png, info); if (png && info && end) {
success = success && PNGReadPixels(png, info, pixels, w, h, w); success = PNGReadHeader(png, info);
success = success && PNGReadFooter(png, end); success = success && PNGReadPixels(png, info, pixels, w, h, w);
success = success && PNGReadFooter(png, end);
}
PNGReadClose(png, info, end);
}
if (vf) {
vf->close(vf);
}
if (success) {
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, w, h, true);
gbaBackground->screenshotId = stateId | SCREENSHOT_VALID;
} else {
gbaBackground->screenshotId = stateId | SCREENSHOT_INVALID;
} }
PNGReadClose(png, info, end);
} }
if (vf) { if (gbaBackground->p->drawFrame && gbaBackground->screenshotId == (stateId | SCREENSHOT_INVALID)) {
vf->close(vf);
}
if (success) {
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, w, h, true);
gbaBackground->screenshotId = (int) id;
} else if (gbaBackground->p->drawFrame) {
gbaBackground->p->drawFrame(gbaBackground->p, true); gbaBackground->p->drawFrame(gbaBackground->p, true);
} }
} }
@ -315,7 +330,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
.draw = _drawState .draw = _drawState
}, },
.p = runner, .p = runner,
.screenshot = 0, .image = 0,
.screenshotId = 0 .screenshotId = 0
}; };
struct GUIMenu pauseMenu = { struct GUIMenu pauseMenu = {
@ -628,10 +643,10 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
runner->core->reset(runner->core); runner->core->reset(runner->core);
break; break;
case RUNNER_SAVE_STATE: case RUNNER_SAVE_STATE:
mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA); mCoreSaveState(runner->core, ((uint32_t) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
break; break;
case RUNNER_LOAD_STATE: case RUNNER_LOAD_STATE:
mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); mCoreLoadState(runner->core, ((uint32_t) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
break; break;
case RUNNER_SCREENSHOT: case RUNNER_SCREENSHOT:
mCoreTakeScreenshot(runner->core); mCoreTakeScreenshot(runner->core);
@ -696,10 +711,8 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
mLOG(GUI_RUNNER, DEBUG, "Unloading game..."); mLOG(GUI_RUNNER, DEBUG, "Unloading game...");
runner->core->unloadROM(runner->core); runner->core->unloadROM(runner->core);
drawState.screenshotId = 0; drawState.screenshotId = 0;
if (drawState.screenshot) { if (drawState.image) {
unsigned w, h; mappedMemoryFree(drawState.image, drawState.imageSize);
runner->core->desiredVideoDimensions(runner->core, &w, &h);
mappedMemoryFree(drawState.screenshot, w * h * 4);
} }
if (runner->config.port) { if (runner->config.port) {

View File

@ -31,8 +31,10 @@ struct mGUIBackground {
struct GUIBackground d; struct GUIBackground d;
struct mGUIRunner* p; struct mGUIRunner* p;
color_t* screenshot; color_t* image;
int screenshotId; size_t imageSize;
unsigned screenshotId;
}; };
struct mCore; struct mCore;