all repos — mgba @ 570f2c5f380464ae7f6d468242151d520cb00c15

mGBA Game Boy Advance Emulator

Core: Video packet injection
Vicki Pfau vi@endrift.com
Sat, 01 Jun 2019 14:28:39 -0700
commit

570f2c5f380464ae7f6d468242151d520cb00c15

parent

4420054c1a3b13e406e28aaa7ab8f44ab3509438

2 files changed, 101 insertions(+), 15 deletions(-)

jump to
M include/mgba/feature/video-logger.hinclude/mgba/feature/video-logger.h

@@ -35,6 +35,11 @@ LOGGER_EVENT_RESET,

LOGGER_EVENT_GET_PIXELS, }; +enum mVideoLoggerInjectionPoint { + LOGGER_INJECTION_IMMEDIATE = 0, + LOGGER_INJECTION_FIRST_SCANLINE, +}; + struct mVideoLoggerDirtyInfo { enum mVideoLoggerDirtyType type; uint32_t address;

@@ -97,6 +102,7 @@ void mVideoLoggerRendererFlush(struct mVideoLogger* logger);

void mVideoLoggerRendererFinishFrame(struct mVideoLogger* logger); bool mVideoLoggerRendererRun(struct mVideoLogger* logger, bool block); +bool mVideoLoggerRendererRunInjected(struct mVideoLogger* logger); struct mVideoLogContext; void mVideoLoggerAttachChannel(struct mVideoLogger* logger, struct mVideoLogContext* context, size_t channelId);

@@ -115,6 +121,12 @@ void mVideoLogContextRewind(struct mVideoLogContext*, struct mCore*);

void* mVideoLogContextInitialState(struct mVideoLogContext*, size_t* size); int mVideoLoggerAddChannel(struct mVideoLogContext*); + +void mVideoLoggerInjectionPoint(struct mVideoLogger* logger, enum mVideoLoggerInjectionPoint); +void mVideoLoggerIgnoreAfterInjection(struct mVideoLogger* logger, uint32_t mask); +void mVideoLoggerInjectVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerInjectPalette(struct mVideoLogger* logger, uint32_t address, uint16_t value); +void mVideoLoggerInjectOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value); struct mCore* mVideoLogCoreFind(struct VFile*);
M src/feature/video-logger.csrc/feature/video-logger.c

@@ -84,6 +84,11 @@ bool inflating;

z_stream inflateStream; #endif + bool injecting; + enum mVideoLoggerInjectionPoint injectionPoint; + uint32_t ignorePackets; + + struct CircleBuffer injectedBuffer; struct CircleBuffer buffer; };

@@ -286,14 +291,28 @@ logger->writeData(logger, data, length);

} bool mVideoLoggerRendererRun(struct mVideoLogger* logger, bool block) { + struct mVideoLogChannel* channel = logger->dataContext; + uint32_t ignorePackets = 0; + if (channel->injectionPoint == LOGGER_INJECTION_IMMEDIATE && !channel->injecting) { + mVideoLoggerRendererRunInjected(logger); + ignorePackets = channel->ignorePackets; + } struct mVideoLoggerDirtyInfo item = {0}; while (logger->readData(logger, &item, sizeof(item), block)) { + if (ignorePackets & (1 << item.type)) { + continue; + } switch (item.type) { + case DIRTY_SCANLINE: + if (channel->injectionPoint == LOGGER_INJECTION_FIRST_SCANLINE && !channel->injecting && item.address == 0) { + mVideoLoggerRendererRunInjected(logger); + ignorePackets = channel->ignorePackets; + } + // Fall through case DIRTY_REGISTER: case DIRTY_PALETTE: case DIRTY_OAM: case DIRTY_VRAM: - case DIRTY_SCANLINE: case DIRTY_FLUSH: case DIRTY_FRAME: case DIRTY_RANGE:

@@ -309,15 +328,34 @@ }

return !block; } +bool mVideoLoggerRendererRunInjected(struct mVideoLogger* logger) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->injecting = true; + bool res = mVideoLoggerRendererRun(logger, false); + channel->injecting = false; + return res; +} + +void mVideoLoggerInjectionPoint(struct mVideoLogger* logger, enum mVideoLoggerInjectionPoint injectionPoint) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->injectionPoint = injectionPoint; +} + +void mVideoLoggerIgnoreAfterInjection(struct mVideoLogger* logger, uint32_t mask) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->ignorePackets = mask; +} + static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length) { struct mVideoLogChannel* channel = logger->dataContext; return mVideoLoggerWriteChannel(channel, data, length) == (ssize_t) length; } static bool _writeNull(struct mVideoLogger* logger, const void* data, size_t length) { - UNUSED(logger); - UNUSED(data); - UNUSED(length); + struct mVideoLogChannel* channel = logger->dataContext; + if (channel->injecting) { + return mVideoLoggerWriteChannel(channel, data, length) == (ssize_t) length; + } return false; }

@@ -623,6 +661,7 @@ off_t pointer = context->backing->seek(context->backing, 0, SEEK_CUR);

size_t i; for (i = 0; i < context->nChannels; ++i) { + CircleBufferInit(&context->channels[i].injectedBuffer, BUFFER_BASE_SIZE); CircleBufferInit(&context->channels[i].buffer, BUFFER_BASE_SIZE); context->channels[i].bufferRemaining = 0; context->channels[i].currentPointer = pointer;

@@ -703,6 +742,7 @@ }

size_t i; for (i = 0; i < context->nChannels; ++i) { + CircleBufferDeinit(&context->channels[i].injectedBuffer); CircleBufferDeinit(&context->channels[i].buffer); #ifdef USE_ZLIB if (context->channels[i].inflating) {

@@ -733,6 +773,7 @@ off_t pointer = context->backing->seek(context->backing, 0, SEEK_CUR);

size_t i; for (i = 0; i < context->nChannels; ++i) { + CircleBufferClear(&context->channels[i].injectedBuffer); CircleBufferClear(&context->channels[i].buffer); context->channels[i].bufferRemaining = 0; context->channels[i].currentPointer = pointer;

@@ -759,8 +800,33 @@ }

int chid = context->nChannels; ++context->nChannels; context->channels[chid].p = context; + CircleBufferInit(&context->channels[chid].injectedBuffer, BUFFER_BASE_SIZE); CircleBufferInit(&context->channels[chid].buffer, BUFFER_BASE_SIZE); + context->channels[chid].injecting = false; + context->channels[chid].injectionPoint = LOGGER_INJECTION_IMMEDIATE; + context->channels[chid].ignorePackets = 0; return chid; +} + +void mVideoLoggerInjectVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->injecting = true; + mVideoLoggerRendererWriteVideoRegister(logger, address, value); + channel->injecting = false; +} + +void mVideoLoggerInjectPalette(struct mVideoLogger* logger, uint32_t address, uint16_t value) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->injecting = true; + mVideoLoggerRendererWritePalette(logger, address, value); + channel->injecting = false; +} + +void mVideoLoggerInjectOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value) { + struct mVideoLogChannel* channel = logger->dataContext; + channel->injecting = true; + mVideoLoggerRendererWriteOAM(logger, address, value); + channel->injecting = false; } #ifdef USE_ZLIB

@@ -915,12 +981,16 @@ unsigned channelId = channel - context->channels;

if (channelId >= mVL_MAX_CHANNELS) { return 0; } - if (CircleBufferSize(&channel->buffer) >= length) { - return CircleBufferRead(&channel->buffer, data, length); + struct CircleBuffer* buffer = &channel->buffer; + if (channel->injecting) { + buffer = &channel->injectedBuffer; + } + if (CircleBufferSize(buffer) >= length) { + return CircleBufferRead(buffer, data, length); } ssize_t size = 0; - if (CircleBufferSize(&channel->buffer)) { - size = CircleBufferRead(&channel->buffer, data, CircleBufferSize(&channel->buffer)); + if (CircleBufferSize(buffer)) { + size = CircleBufferRead(buffer, data, CircleBufferSize(buffer)); if (size <= 0) { return size; }

@@ -930,7 +1000,7 @@ }

if (!_fillBuffer(context, channelId, BUFFER_BASE_SIZE)) { return size; } - size += CircleBufferRead(&channel->buffer, data, length); + size += CircleBufferRead(buffer, data, length); return size; }

@@ -944,16 +1014,20 @@ if (channelId != context->activeChannel) {

_flushBuffer(context); context->activeChannel = channelId; } - if (CircleBufferCapacity(&channel->buffer) - CircleBufferSize(&channel->buffer) < length) { + struct CircleBuffer* buffer = &channel->buffer; + if (channel->injecting) { + buffer = &channel->injectedBuffer; + } + if (CircleBufferCapacity(buffer) - CircleBufferSize(buffer) < length) { _flushBuffer(context); - if (CircleBufferCapacity(&channel->buffer) < length) { - CircleBufferDeinit(&channel->buffer); - CircleBufferInit(&channel->buffer, toPow2(length << 1)); + if (CircleBufferCapacity(buffer) < length) { + CircleBufferDeinit(buffer); + CircleBufferInit(buffer, toPow2(length << 1)); } } - ssize_t read = CircleBufferWrite(&channel->buffer, data, length); - if (CircleBufferCapacity(&channel->buffer) == CircleBufferSize(&channel->buffer)) { + ssize_t read = CircleBufferWrite(buffer, data, length); + if (CircleBufferCapacity(buffer) == CircleBufferSize(buffer)) { _flushBuffer(context); } return read;