mirror of https://github.com/mgba-emu/mgba.git
Core: Video packet injection
This commit is contained in:
parent
4420054c1a
commit
570f2c5f38
|
@ -35,6 +35,11 @@ enum mVideoLoggerEvent {
|
|||
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);
|
||||
|
@ -116,6 +122,12 @@ 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*);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
|
|
@ -84,6 +84,11 @@ struct mVideoLogChannel {
|
|||
z_stream inflateStream;
|
||||
#endif
|
||||
|
||||
bool injecting;
|
||||
enum mVideoLoggerInjectionPoint injectionPoint;
|
||||
uint32_t ignorePackets;
|
||||
|
||||
struct CircleBuffer injectedBuffer;
|
||||
struct CircleBuffer buffer;
|
||||
};
|
||||
|
||||
|
@ -286,14 +291,28 @@ void mVideoLoggerWriteBuffer(struct mVideoLogger* logger, uint32_t bufferId, uin
|
|||
}
|
||||
|
||||
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 @@ bool mVideoLoggerRendererRun(struct mVideoLogger* logger, bool block) {
|
|||
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 @@ bool mVideoLogContextLoad(struct mVideoLogContext* context, struct VFile* vf) {
|
|||
|
||||
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 @@ void mVideoLogContextDestroy(struct mCore* core, struct mVideoLogContext* contex
|
|||
|
||||
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 @@ void mVideoLogContextRewind(struct mVideoLogContext* context, struct mCore* core
|
|||
|
||||
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,10 +800,35 @@ int mVideoLoggerAddChannel(struct mVideoLogContext* context) {
|
|||
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
|
||||
static size_t _readBufferCompressed(struct VFile* vf, struct mVideoLogChannel* channel, size_t length) {
|
||||
uint8_t fbuffer[0x400];
|
||||
|
@ -915,12 +981,16 @@ static ssize_t mVideoLoggerReadChannel(struct mVideoLogChannel* channel, void* d
|
|||
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 @@ static ssize_t mVideoLoggerReadChannel(struct mVideoLogChannel* channel, void* d
|
|||
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 @@ static ssize_t mVideoLoggerWriteChannel(struct mVideoLogChannel* channel, const
|
|||
_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;
|
||||
|
|
Loading…
Reference in New Issue