Core: Begin splitting threading out from GBA proxy

This commit is contained in:
Vicki Pfau 2017-04-13 22:13:26 -07:00
parent 11edac0aa4
commit eab5ed6e14
3 changed files with 88 additions and 49 deletions

View File

@ -28,10 +28,13 @@ struct mVideoProxyDirtyInfo {
}; };
struct mVideoProxy { struct mVideoProxy {
bool (*writeData)(struct mVideoProxy* proxy, void* data, size_t length); bool (*writeData)(struct mVideoProxy* proxy, const void* data, size_t length);
uint16_t* (*vramBlock)(struct mVideoProxy* proxy, uint32_t address); bool (*readData)(struct mVideoProxy* proxy, void* data, size_t length, bool block);
void* context; void* context;
bool (*parsePacket)(struct mVideoProxy* proxy, const struct mVideoProxyDirtyInfo* packet);
uint16_t* (*vramBlock)(struct mVideoProxy* proxy, uint32_t address);
size_t vramSize; size_t vramSize;
size_t oamSize; size_t oamSize;
size_t paletteSize; size_t paletteSize;
@ -56,6 +59,8 @@ void mVideoProxyRendererWriteOAM(struct mVideoProxy* proxy, uint32_t address, ui
void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y); void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y);
void mVideoProxyRendererFlush(struct mVideoProxy* proxy); void mVideoProxyRendererFlush(struct mVideoProxy* proxy);
bool mVideoProxyRendererRun(struct mVideoProxy* proxy);
CXX_GUARD_END CXX_GUARD_END
#endif #endif

View File

@ -104,7 +104,6 @@ void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y) {
proxy->writeData(proxy, &dirty, sizeof(dirty)); proxy->writeData(proxy, &dirty, sizeof(dirty));
} }
void mVideoProxyRendererFlush(struct mVideoProxy* proxy) { void mVideoProxyRendererFlush(struct mVideoProxy* proxy) {
struct mVideoProxyDirtyInfo dirty = { struct mVideoProxyDirtyInfo dirty = {
DIRTY_FLUSH, DIRTY_FLUSH,
@ -114,3 +113,24 @@ void mVideoProxyRendererFlush(struct mVideoProxy* proxy) {
}; };
proxy->writeData(proxy, &dirty, sizeof(dirty)); 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;
}

View File

@ -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 * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -27,7 +27,9 @@ static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* render
static THREAD_ENTRY _proxyThread(void* renderer); 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); static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address);
void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) { void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
@ -51,6 +53,8 @@ void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* rende
renderer->proxy.context = renderer; renderer->proxy.context = renderer;
renderer->proxy.writeData = _writeData; renderer->proxy.writeData = _writeData;
renderer->proxy.readData = _readData;
renderer->proxy.parsePacket = _parsePacket;
renderer->proxy.vramBlock = _vramBlock; renderer->proxy.vramBlock = _vramBlock;
renderer->proxy.paletteSize = SIZE_PALETTE_RAM; renderer->proxy.paletteSize = SIZE_PALETTE_RAM;
renderer->proxy.vramSize = SIZE_VRAM; renderer->proxy.vramSize = SIZE_VRAM;
@ -134,7 +138,7 @@ void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer); 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; struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) { while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) {
mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length); mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);
@ -151,6 +155,52 @@ static bool _writeData(struct mVideoProxy* proxy, void* data, size_t length) {
return true; 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) { static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context; struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
return &proxyRenderer->d.vram[address >> 1]; return &proxyRenderer->d.vram[address >> 1];
@ -262,55 +312,19 @@ static THREAD_ENTRY _proxyThread(void* renderer) {
ThreadSetName("Proxy Renderer Thread"); ThreadSetName("Proxy Renderer Thread");
MutexLock(&proxyRenderer->mutex); MutexLock(&proxyRenderer->mutex);
struct mVideoProxyDirtyInfo item = {0};
while (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { while (proxyRenderer->threadState != PROXY_THREAD_STOPPED) {
ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex); ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex);
if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) { if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) {
break; break;
} }
if (RingFIFORead(&proxyRenderer->dirtyQueue, &item, sizeof(item))) { proxyRenderer->threadState = PROXY_THREAD_BUSY;
proxyRenderer->threadState = PROXY_THREAD_BUSY; MutexUnlock(&proxyRenderer->mutex);
MutexUnlock(&proxyRenderer->mutex); if (!mVideoProxyRendererRun(&proxyRenderer->proxy)) {
do { // FIFO was corrupted
switch (item.type) { proxyRenderer->threadState = PROXY_THREAD_STOPPED;
case DIRTY_REGISTER: mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!");
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);
} }
out: MutexLock(&proxyRenderer->mutex);
ConditionWake(&proxyRenderer->fromThreadCond); ConditionWake(&proxyRenderer->fromThreadCond);
if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) {
proxyRenderer->threadState = PROXY_THREAD_IDLE; proxyRenderer->threadState = PROXY_THREAD_IDLE;