GBA Video: Add stubs for saving/loading extra data out of the video renderers

This commit is contained in:
Vicki Pfau 2024-09-01 01:56:52 -07:00
parent da553d191f
commit a5ea157c9a
7 changed files with 156 additions and 6 deletions

View File

@ -35,6 +35,8 @@ enum mVideoLoggerEvent {
LOGGER_EVENT_DEINIT,
LOGGER_EVENT_RESET,
LOGGER_EVENT_GET_PIXELS,
LOGGER_EVENT_LOAD_STATE,
LOGGER_EVENT_SAVE_STATE,
};
enum mVideoLoggerInjectionPoint {
@ -85,6 +87,10 @@ struct mVideoLogger {
const void* pixelBuffer;
size_t pixelStride;
void* stateBuffer;
size_t stateSize;
bool stateStatus;
};
void mVideoLoggerRendererCreate(struct mVideoLogger* logger, bool readonly);

View File

@ -285,6 +285,11 @@ DECL_BIT(GBASerializedMiscFlags, IrqPending, 2);
DECL_BIT(GBASerializedMiscFlags, Blocked, 3);
DECL_BITS(GBASerializedMiscFlags, KeyIRQKeys, 4, 11);
enum {
GBA_SUBSYSTEM_VIDEO_RENDERER = 0,
GBA_SUBSYSTEM_MAX,
};
struct GBASerializedState {
uint32_t versionMagic;
uint32_t biosChecksum;

View File

@ -182,6 +182,10 @@ struct GBAVideoRenderer {
void (*reset)(struct GBAVideoRenderer* renderer);
void (*deinit)(struct GBAVideoRenderer* renderer);
uint32_t (*rendererId)(const struct GBAVideoRenderer* renderer);
bool (*loadState)(struct GBAVideoRenderer* renderer, const void* state, size_t size);
void (*saveState)(struct GBAVideoRenderer* renderer, void** state, size_t* size);
uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
void (*writeVRAM)(struct GBAVideoRenderer* renderer, uint32_t address);
void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);

View File

@ -7,6 +7,7 @@
#include <mgba/core/core.h>
#include <mgba/core/log.h>
#include <mgba/core/serialize.h>
#include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/internal/arm/isa-inlines.h>
#include <mgba/internal/debugger/symbols.h>
@ -833,14 +834,44 @@ static bool _GBACoreSaveState(struct mCore* core, void* state) {
}
static bool _GBACoreLoadExtraState(struct mCore* core, const struct mStateExtdata* extdata) {
UNUSED(core);
UNUSED(extdata);
return true;
struct GBA* gba = core->board;
struct mStateExtdataItem item;
bool ok = true;
if (mStateExtdataGet(extdata, EXTDATA_SUBSYSTEM_START + GBA_SUBSYSTEM_VIDEO_RENDERER, &item)) {
if ((uint32_t) item.size > sizeof(uint32_t)) {
uint32_t type;
LOAD_32(type, 0, item.data);
if (type == gba->video.renderer->rendererId(gba->video.renderer)) {
ok = gba->video.renderer->loadState(gba->video.renderer,
(void*) ((uintptr_t) item.data + sizeof(uint32_t)),
item.size - sizeof(type));
}
} else if (item.data) {
ok = false;
}
}
return ok;
}
static bool _GBACoreSaveExtraState(struct mCore* core, struct mStateExtdata* extdata) {
UNUSED(core);
UNUSED(extdata);
struct GBA* gba = core->board;
void* buffer = NULL;
size_t size = 0;
gba->video.renderer->saveState(gba->video.renderer, &buffer, &size);
if (size > 0 && buffer) {
struct mStateExtdataItem item;
item.size = size + sizeof(uint32_t);
item.data = malloc(item.size);
item.clean = free;
uint32_t type = gba->video.renderer->rendererId(gba->video.renderer);
STORE_32(type, 0, item.data);
memcpy((void*) ((uintptr_t) item.data + sizeof(uint32_t)), buffer, size);
mStateExtdataPut(extdata, EXTDATA_SUBSYSTEM_START + GBA_SUBSYSTEM_VIDEO_RENDERER, &item);
}
if (buffer) {
free(buffer);
}
return true;
}

View File

@ -13,6 +13,9 @@
static void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer);
static void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer);
static uint32_t GBAVideoProxyRendererId(const struct GBAVideoRenderer* renderer);
static bool GBAVideoProxyRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size);
static void GBAVideoProxyRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size);
static uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
@ -27,9 +30,13 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address);
void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
memset(renderer, 0, sizeof(*renderer));
renderer->d.init = GBAVideoProxyRendererInit;
renderer->d.reset = GBAVideoProxyRendererReset;
renderer->d.deinit = GBAVideoProxyRendererDeinit;
renderer->d.rendererId = GBAVideoProxyRendererId;
renderer->d.loadState = GBAVideoProxyRendererLoadState;
renderer->d.saveState = GBAVideoProxyRendererSaveState;
renderer->d.writeVideoRegister = GBAVideoProxyRendererWriteVideoRegister;
renderer->d.writeVRAM = GBAVideoProxyRendererWriteVRAM;
renderer->d.writeOAM = GBAVideoProxyRendererWriteOAM;
@ -172,6 +179,11 @@ void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
mVideoLoggerRendererDeinit(proxyRenderer->logger);
}
uint32_t GBAVideoProxyRendererId(const struct GBAVideoRenderer* renderer) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
return proxyRenderer->backend->rendererId(proxyRenderer->backend);
}
static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) {
struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
switch (event) {
@ -189,6 +201,12 @@ static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent eve
case LOGGER_EVENT_GET_PIXELS:
proxyRenderer->backend->getPixels(proxyRenderer->backend, &logger->pixelStride, &logger->pixelBuffer);
break;
case LOGGER_EVENT_LOAD_STATE:
logger->stateStatus = proxyRenderer->backend->loadState(proxyRenderer->backend, logger->stateBuffer, logger->stateSize);
break;
case LOGGER_EVENT_SAVE_STATE:
proxyRenderer->backend->saveState(proxyRenderer->backend, &logger->stateBuffer, &logger->stateSize);
break;
}
}
@ -279,6 +297,35 @@ uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* render
return value;
}
bool GBAVideoProxyRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
proxyRenderer->logger->wait(proxyRenderer->logger);
proxyRenderer->logger->stateBuffer = (void*) state;
proxyRenderer->logger->stateSize = size;
proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_LOAD_STATE);
proxyRenderer->logger->stateBuffer = NULL;
proxyRenderer->logger->stateSize = 0;
return proxyRenderer->logger->stateStatus;
} else {
return proxyRenderer->backend->loadState(proxyRenderer->backend, state, size);
}
}
void GBAVideoProxyRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
proxyRenderer->logger->wait(proxyRenderer->logger);
proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_SAVE_STATE);
*state = proxyRenderer->logger->stateBuffer;
*size = proxyRenderer->logger->stateSize;
proxyRenderer->logger->stateBuffer = NULL;
proxyRenderer->logger->stateSize = 0;
} else {
proxyRenderer->backend->saveState(proxyRenderer->backend, state, size);
}
}
void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);

View File

@ -13,9 +13,14 @@
#include <mgba/internal/gba/renderers/cache-set.h>
#include <mgba-util/memory.h>
#define OPENGL_MAGIC 0x6E726C67
static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer);
static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer);
static uint32_t GBAVideoGLRendererId(const struct GBAVideoRenderer* renderer);
static bool GBAVideoGLRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size);
static void GBAVideoGLRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size);
static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
@ -656,9 +661,13 @@ static const GLint _vertices[] = {
};
void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
memset(renderer, 0, sizeof(*renderer));
renderer->d.init = GBAVideoGLRendererInit;
renderer->d.reset = GBAVideoGLRendererReset;
renderer->d.deinit = GBAVideoGLRendererDeinit;
renderer->d.rendererId = GBAVideoGLRendererId;
renderer->d.loadState = GBAVideoGLRendererLoadState;
renderer->d.saveState = GBAVideoGLRendererSaveState;
renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
@ -953,6 +962,26 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
}
}
static uint32_t GBAVideoGLRendererId(const struct GBAVideoRenderer* renderer) {
UNUSED(renderer);
return OPENGL_MAGIC;
}
static bool GBAVideoGLRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size) {
UNUSED(renderer);
UNUSED(state);
UNUSED(size);
// TODO
return false;
}
static void GBAVideoGLRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size) {
UNUSED(renderer);
*state = NULL;
*size = 0;
// TODO
}
void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
if (renderer->cache) {

View File

@ -14,10 +14,14 @@
#define DIRTY_SCANLINE(R, Y) R->scanlineDirty[Y >> 5] |= (1U << (Y & 0x1F))
#define CLEAN_SCANLINE(R, Y) R->scanlineDirty[Y >> 5] &= ~(1U << (Y & 0x1F))
#define SOFTWARE_MAGIC 0x6E727773
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer);
static uint32_t GBAVideoSoftwareRendererId(const struct GBAVideoRenderer* renderer);
static bool GBAVideoSoftwareRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size);
static void GBAVideoSoftwareRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size);
static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
@ -47,9 +51,13 @@ static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, stru
static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win);
void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
memset(renderer, 0, sizeof(*renderer));
renderer->d.init = GBAVideoSoftwareRendererInit;
renderer->d.reset = GBAVideoSoftwareRendererReset;
renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
renderer->d.rendererId = GBAVideoSoftwareRendererId;
renderer->d.loadState = GBAVideoSoftwareRendererLoadState;
renderer->d.saveState = GBAVideoSoftwareRendererSaveState;
renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
renderer->d.writeVRAM = GBAVideoSoftwareRendererWriteVRAM;
renderer->d.writeOAM = GBAVideoSoftwareRendererWriteOAM;
@ -79,7 +87,7 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
renderer->d.highlightColor = M_COLOR_WHITE;
renderer->d.highlightAmount = 0;
renderer->temporaryBuffer = 0;
renderer->temporaryBuffer = NULL;
}
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {
@ -155,6 +163,26 @@ static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer) {
UNUSED(softwareRenderer);
}
static uint32_t GBAVideoSoftwareRendererId(const struct GBAVideoRenderer* renderer) {
UNUSED(renderer);
return SOFTWARE_MAGIC;
}
static bool GBAVideoSoftwareRendererLoadState(struct GBAVideoRenderer* renderer, const void* state, size_t size) {
UNUSED(renderer);
UNUSED(state);
UNUSED(size);
// TODO
return false;
}
static void GBAVideoSoftwareRendererSaveState(struct GBAVideoRenderer* renderer, void** state, size_t* size) {
UNUSED(renderer);
*state = NULL;
*size = 0;
// TODO
}
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
if (renderer->cache) {