all repos — mgba @ eab5ed6e142e75656adbe918f2422d936f67c5c2

mGBA Game Boy Advance Emulator

Core: Begin splitting threading out from GBA proxy
Vicki Pfau vi@endrift.com
Thu, 13 Apr 2017 22:13:26 -0700
commit

eab5ed6e142e75656adbe918f2422d936f67c5c2

parent

11edac0aa453e3735e4405b8165a2975e7d555f1

3 files changed, 88 insertions(+), 49 deletions(-)

jump to
M include/mgba/core/video-proxy.hinclude/mgba/core/video-proxy.h

@@ -28,9 +28,12 @@ uint32_t padding;

}; struct mVideoProxy { - bool (*writeData)(struct mVideoProxy* proxy, void* data, size_t length); + bool (*writeData)(struct mVideoProxy* proxy, const void* data, size_t length); + bool (*readData)(struct mVideoProxy* proxy, void* data, size_t length, bool block); + void* context; + + bool (*parsePacket)(struct mVideoProxy* proxy, const struct mVideoProxyDirtyInfo* packet); uint16_t* (*vramBlock)(struct mVideoProxy* proxy, uint32_t address); - void* context; size_t vramSize; size_t oamSize;

@@ -55,6 +58,8 @@ void mVideoProxyRendererWriteOAM(struct mVideoProxy* proxy, uint32_t address, uint16_t value);

void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y); void mVideoProxyRendererFlush(struct mVideoProxy* proxy); + +bool mVideoProxyRendererRun(struct mVideoProxy* proxy); CXX_GUARD_END
M src/core/video-proxy.csrc/core/video-proxy.c

@@ -104,7 +104,6 @@ };

proxy->writeData(proxy, &dirty, sizeof(dirty)); } - void mVideoProxyRendererFlush(struct mVideoProxy* proxy) { struct mVideoProxyDirtyInfo dirty = { DIRTY_FLUSH,

@@ -114,3 +113,24 @@ 0xDEADBEEF,

}; proxy->writeData(proxy, &dirty, sizeof(dirty)); } + +bool mVideoProxyRendererRun(struct mVideoProxy* proxy) { + struct mVideoProxyDirtyInfo item = {0}; + while (proxy->readData(proxy, &item, sizeof(item), false)) { + switch (item.type) { + case DIRTY_REGISTER: + case DIRTY_PALETTE: + case DIRTY_OAM: + case DIRTY_VRAM: + case DIRTY_SCANLINE: + case DIRTY_FLUSH: + if (!proxy->parsePacket(proxy, &item)) { + return true; + } + break; + default: + return false; + } + } + return true; +}
M src/gba/renderers/thread-proxy.csrc/gba/renderers/thread-proxy.c

@@ -1,4 +1,4 @@

-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2017 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this

@@ -27,7 +27,9 @@ static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);

static THREAD_ENTRY _proxyThread(void* renderer); -static bool _writeData(struct mVideoProxy* proxy, void* data, size_t length); +static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t length); +static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool block); +static bool _parsePacket(struct mVideoProxy* proxy, const struct mVideoProxyDirtyInfo* packet); static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address); void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) {

@@ -51,6 +53,8 @@ renderer->d.disableOBJ = false;

renderer->proxy.context = renderer; renderer->proxy.writeData = _writeData; + renderer->proxy.readData = _readData; + renderer->proxy.parsePacket = _parsePacket; renderer->proxy.vramBlock = _vramBlock; renderer->proxy.paletteSize = SIZE_PALETTE_RAM; renderer->proxy.vramSize = SIZE_VRAM;

@@ -134,7 +138,7 @@ proxyRenderer->threadState = PROXY_THREAD_IDLE;

ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer); } -static bool _writeData(struct mVideoProxy* proxy, void* data, size_t length) { +static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t length) { struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context; while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) { mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);

@@ -151,6 +155,52 @@ }

return true; } +static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool block) { + struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context; + bool read = false; + while (true) { + read = RingFIFORead(&proxyRenderer->dirtyQueue, data, length); + if (!block || read) { + break; + } + mLOG(GBA_VIDEO, DEBUG, "Proxy thread can't read VRAM. CPU thread asleep?"); + MutexLock(&proxyRenderer->mutex); + ConditionWake(&proxyRenderer->fromThreadCond); + ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex); + MutexUnlock(&proxyRenderer->mutex); + } + return read; +} + +static bool _parsePacket(struct mVideoProxy* proxy, const struct mVideoProxyDirtyInfo* item) { + struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context; + switch (item->type) { + case DIRTY_REGISTER: + proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value); + break; + case DIRTY_PALETTE: + proxy->palette[item->address >> 1] = item->value; + proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value); + break; + case DIRTY_OAM: + proxy->oam[item->address] = item->value; + proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address); + break; + case DIRTY_VRAM: + proxy->readData(proxy, &proxy->vram[item->address >> 1], 0x1000, true); + proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address); + break; + case DIRTY_SCANLINE: + proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address); + break; + case DIRTY_FLUSH: + return false; + default: + return false; + } + return true; +} + static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address) { struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context; return &proxyRenderer->d.vram[address >> 1];

@@ -262,55 +312,19 @@ struct GBAVideoThreadProxyRenderer* proxyRenderer = renderer;

ThreadSetName("Proxy Renderer Thread"); MutexLock(&proxyRenderer->mutex); - struct mVideoProxyDirtyInfo item = {0}; while (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex); if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) { break; } - if (RingFIFORead(&proxyRenderer->dirtyQueue, &item, sizeof(item))) { - proxyRenderer->threadState = PROXY_THREAD_BUSY; - MutexUnlock(&proxyRenderer->mutex); - do { - switch (item.type) { - case DIRTY_REGISTER: - proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item.address, item.value); - break; - case DIRTY_PALETTE: - proxyRenderer->proxy.palette[item.address >> 1] = item.value; - proxyRenderer->backend->writePalette(proxyRenderer->backend, item.address, item.value); - break; - case DIRTY_OAM: - proxyRenderer->proxy.oam[item.address] = item.value; - proxyRenderer->backend->writeOAM(proxyRenderer->backend, item.address); - break; - case DIRTY_VRAM: - while (!RingFIFORead(&proxyRenderer->dirtyQueue, &proxyRenderer->proxy.vram[item.address >> 1], 0x1000)) { - mLOG(GBA_VIDEO, DEBUG, "Proxy thread can't read VRAM. CPU thread asleep?"); - MutexLock(&proxyRenderer->mutex); - ConditionWake(&proxyRenderer->fromThreadCond); - ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex); - MutexUnlock(&proxyRenderer->mutex); - } - proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item.address); - break; - case DIRTY_SCANLINE: - proxyRenderer->backend->drawScanline(proxyRenderer->backend, item.address); - break; - case DIRTY_FLUSH: - MutexLock(&proxyRenderer->mutex); - goto out; - default: - // FIFO was corrupted - MutexLock(&proxyRenderer->mutex); - proxyRenderer->threadState = PROXY_THREAD_STOPPED; - mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); - goto out; - } - } while (proxyRenderer->threadState == PROXY_THREAD_BUSY && RingFIFORead(&proxyRenderer->dirtyQueue, &item, sizeof(item))); - MutexLock(&proxyRenderer->mutex); + proxyRenderer->threadState = PROXY_THREAD_BUSY; + MutexUnlock(&proxyRenderer->mutex); + if (!mVideoProxyRendererRun(&proxyRenderer->proxy)) { + // FIFO was corrupted + proxyRenderer->threadState = PROXY_THREAD_STOPPED; + mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); } - out: + MutexLock(&proxyRenderer->mutex); ConditionWake(&proxyRenderer->fromThreadCond); if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { proxyRenderer->threadState = PROXY_THREAD_IDLE;