Restore pixels from PNG when loading savestate
Jeffrey Pfau jeffrey@endrift.com
Sat, 26 Jul 2014 14:06:28 -0700
6 files changed,
58 insertions(+),
3 deletions(-)
M
src/gba/gba-serialize.c
→
src/gba/gba-serialize.c
@@ -130,11 +130,15 @@ if (!png || !info || !end) {
PNGReadClose(png, info, end); return false; } + uint32_t pixels[VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4]; + PNGInstallChunkHandler(png, gba, _loadPNGChunkHandler, "gbAs"); PNGReadHeader(png, info); - PNGIgnorePixels(png, info); + PNGReadPixels(png, info, &pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS); PNGReadFooter(png, end); PNGReadClose(png, info, end); + gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, pixels); + GBASyncPostFrame(gba->sync); return true; }
M
src/gba/gba-thread.c
→
src/gba/gba-thread.c
@@ -535,6 +535,10 @@ }
MutexUnlock(&sync->videoFrameMutex); struct GBAThread* thread = GBAThreadGetContext(); + if (!thread) { + return; + } + if (thread->rewindBuffer) { --thread->rewindBufferNext; if (thread->rewindBufferNext <= 0) {@@ -554,10 +558,12 @@ }
MutexLock(&sync->videoFrameMutex); ConditionWake(&sync->videoFrameRequiredCond); - if (!sync->videoFrameOn) { + if (!sync->videoFrameOn && !sync->videoFramePending) { return false; } - ConditionWait(&sync->videoFrameAvailableCond, &sync->videoFrameMutex); + if (!sync->videoFramePending) { + ConditionWait(&sync->videoFrameAvailableCond, &sync->videoFrameMutex); + } sync->videoFramePending = 0; sync->videoFrameSkip = frameskip; return true;
M
src/gba/gba-video.h
→
src/gba/gba-video.h
@@ -185,6 +185,7 @@ void (*drawScanline)(struct GBAVideoRenderer* renderer, int y);
void (*finishFrame)(struct GBAVideoRenderer* renderer); void (*getPixels)(struct GBAVideoRenderer* renderer, unsigned* stride, void** pixels); + void (*putPixels)(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels); uint16_t* palette; uint16_t* vram;
M
src/gba/renderers/video-software.c
→
src/gba/renderers/video-software.c
@@ -30,6 +30,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y); static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoSoftwareRendererGetPixels(struct GBAVideoRenderer* renderer, unsigned* stride, void** pixels); +static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels); static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer); static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value);@@ -69,6 +70,7 @@ renderer->d.writePalette = GBAVideoSoftwareRendererWritePalette;
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline; renderer->d.finishFrame = GBAVideoSoftwareRendererFinishFrame; renderer->d.getPixels = GBAVideoSoftwareRendererGetPixels; + renderer->d.putPixels = GBAVideoSoftwareRendererPutPixels; } static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {@@ -508,6 +510,16 @@ struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
*stride = softwareRenderer->outputBufferStride; *pixels = softwareRenderer->outputBuffer; +} + +static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer, unsigned stride, void* pixels) { + struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; + + uint32_t* colorPixels = pixels; + unsigned i; + for (i = 0; i < VIDEO_VERTICAL_PIXELS; ++i) { + memmove(&softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * i], &colorPixels[stride * i], VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); + } } static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer) {
M
src/util/png-io.c
→
src/util/png-io.c
@@ -135,6 +135,37 @@ }
return true; } +bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { + if (setjmp(png_jmpbuf(png))) { + return false; + } + + uint8_t* pixelData = pixels; + unsigned pngHeight = png_get_image_height(png, info); + if (height > pngHeight) { + height = pngHeight; + } + + unsigned pngWidth = png_get_image_width(png, info); + if (width > pngWidth) { + width = pngWidth; + } + + unsigned i; + png_bytep row = malloc(png_get_rowbytes(png, info)); + for (i = 0; i < height; ++i) { + png_read_row(png, row, 0); + unsigned x; + for (x = 0; x < width; ++x) { + pixelData[stride * i * 4 + x * 4] = row[x * 3]; + pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1]; + pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2]; + } + } + free(row); + return true; +} + bool PNGReadFooter(png_structp png, png_infop end) { if (setjmp(png_jmpbuf(png))) { return false;
M
src/util/png-io.h
→
src/util/png-io.h
@@ -23,6 +23,7 @@ bool isPNG(struct VFile* source);
png_structp PNGReadOpen(struct VFile* source, unsigned offset); bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName); bool PNGReadHeader(png_structp png, png_infop info); +bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride); bool PNGIgnorePixels(png_structp png, png_infop info); bool PNGReadFooter(png_structp png, png_infop end); void PNGReadClose(png_structp png, png_infop info, png_infop end);