Core: Video packet injection

This commit is contained in:
Vicki Pfau 2019-06-01 14:28:39 -07:00
parent 4420054c1a
commit 570f2c5f38
2 changed files with 101 additions and 15 deletions

View File

@ -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

View File

@ -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;