2015-07-29 06:56:45 +00:00
|
|
|
/* Copyright (c) 2013-2015 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
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2016-12-31 01:00:22 +00:00
|
|
|
#include <mgba/internal/gba/renderers/thread-proxy.h>
|
2015-07-29 06:56:45 +00:00
|
|
|
|
2016-12-31 01:00:22 +00:00
|
|
|
#include <mgba/core/tile-cache.h>
|
|
|
|
#include <mgba/internal/gba/gba.h>
|
|
|
|
#include <mgba/internal/gba/io.h>
|
2015-07-29 06:56:45 +00:00
|
|
|
|
2016-12-31 01:00:22 +00:00
|
|
|
#include <mgba-util/memory.h>
|
2015-07-29 06:56:45 +00:00
|
|
|
|
2015-08-30 03:08:00 +00:00
|
|
|
#ifndef DISABLE_THREADING
|
|
|
|
|
2015-07-29 06:56:45 +00:00
|
|
|
static void GBAVideoThreadProxyRendererInit(struct GBAVideoRenderer* renderer);
|
|
|
|
static void GBAVideoThreadProxyRendererReset(struct GBAVideoRenderer* renderer);
|
|
|
|
static void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer);
|
|
|
|
static uint16_t GBAVideoThreadProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
|
|
|
static void GBAVideoThreadProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
|
|
|
|
static void GBAVideoThreadProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
|
|
|
static void GBAVideoThreadProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
|
|
|
|
static void GBAVideoThreadProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
|
|
|
|
static void GBAVideoThreadProxyRendererFinishFrame(struct GBAVideoRenderer* renderer);
|
2016-09-17 10:37:04 +00:00
|
|
|
static void GBAVideoThreadProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
|
|
|
|
static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
|
2015-07-29 06:56:45 +00:00
|
|
|
|
|
|
|
static THREAD_ENTRY _proxyThread(void* renderer);
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
static bool _writeData(struct mVideoProxy* proxy, void* data, size_t length);
|
|
|
|
static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address);
|
|
|
|
|
2015-07-29 06:56:45 +00:00
|
|
|
void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
|
|
|
|
renderer->d.init = GBAVideoThreadProxyRendererInit;
|
|
|
|
renderer->d.reset = GBAVideoThreadProxyRendererReset;
|
|
|
|
renderer->d.deinit = GBAVideoThreadProxyRendererDeinit;
|
|
|
|
renderer->d.writeVideoRegister = GBAVideoThreadProxyRendererWriteVideoRegister;
|
|
|
|
renderer->d.writeVRAM = GBAVideoThreadProxyRendererWriteVRAM;
|
|
|
|
renderer->d.writeOAM = GBAVideoThreadProxyRendererWriteOAM;
|
|
|
|
renderer->d.writePalette = GBAVideoThreadProxyRendererWritePalette;
|
|
|
|
renderer->d.drawScanline = GBAVideoThreadProxyRendererDrawScanline;
|
|
|
|
renderer->d.finishFrame = GBAVideoThreadProxyRendererFinishFrame;
|
|
|
|
renderer->d.getPixels = GBAVideoThreadProxyRendererGetPixels;
|
|
|
|
renderer->d.putPixels = GBAVideoThreadProxyRendererPutPixels;
|
|
|
|
|
|
|
|
renderer->d.disableBG[0] = false;
|
|
|
|
renderer->d.disableBG[1] = false;
|
|
|
|
renderer->d.disableBG[2] = false;
|
|
|
|
renderer->d.disableBG[3] = false;
|
|
|
|
renderer->d.disableOBJ = false;
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
renderer->proxy.context = renderer;
|
|
|
|
renderer->proxy.writeData = _writeData;
|
|
|
|
renderer->proxy.vramBlock = _vramBlock;
|
|
|
|
renderer->proxy.paletteSize = SIZE_PALETTE_RAM;
|
|
|
|
renderer->proxy.vramSize = SIZE_VRAM;
|
|
|
|
renderer->proxy.oamSize = SIZE_OAM;
|
|
|
|
|
2015-07-29 06:56:45 +00:00
|
|
|
renderer->backend = backend;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererInit(struct GBAVideoRenderer* renderer) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
ConditionInit(&proxyRenderer->fromThreadCond);
|
|
|
|
ConditionInit(&proxyRenderer->toThreadCond);
|
|
|
|
MutexInit(&proxyRenderer->mutex);
|
2016-08-15 02:40:24 +00:00
|
|
|
RingFIFOInit(&proxyRenderer->dirtyQueue, 0x40000);
|
2015-07-29 06:56:45 +00:00
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererInit(&proxyRenderer->proxy);
|
|
|
|
|
|
|
|
proxyRenderer->backend->palette = proxyRenderer->proxy.palette;
|
|
|
|
proxyRenderer->backend->vram = proxyRenderer->proxy.vram;
|
|
|
|
proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->proxy.oam;
|
2016-08-10 06:34:36 +00:00
|
|
|
proxyRenderer->backend->cache = NULL;
|
2015-07-29 06:56:45 +00:00
|
|
|
|
|
|
|
proxyRenderer->backend->init(proxyRenderer->backend);
|
|
|
|
|
|
|
|
proxyRenderer->threadState = PROXY_THREAD_IDLE;
|
|
|
|
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererReset(struct GBAVideoRenderer* renderer) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
|
|
|
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
2016-08-10 06:34:36 +00:00
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
2015-07-29 06:56:45 +00:00
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
|
|
}
|
2017-04-14 00:15:16 +00:00
|
|
|
memcpy(proxyRenderer->proxy.oam, &renderer->oam->raw, SIZE_OAM);
|
|
|
|
memcpy(proxyRenderer->proxy.palette, renderer->palette, SIZE_PALETTE_RAM);
|
|
|
|
memcpy(proxyRenderer->proxy.vram, renderer->vram, SIZE_VRAM);
|
|
|
|
|
|
|
|
mVideoProxyRendererReset(&proxyRenderer->proxy);
|
|
|
|
|
2015-07-29 06:56:45 +00:00
|
|
|
proxyRenderer->backend->reset(proxyRenderer->backend);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
bool waiting = false;
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
|
|
|
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
if (proxyRenderer->threadState == PROXY_THREAD_IDLE) {
|
|
|
|
proxyRenderer->threadState = PROXY_THREAD_STOPPED;
|
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
waiting = true;
|
|
|
|
}
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
if (waiting) {
|
|
|
|
ThreadJoin(proxyRenderer->thread);
|
|
|
|
}
|
|
|
|
ConditionDeinit(&proxyRenderer->fromThreadCond);
|
|
|
|
ConditionDeinit(&proxyRenderer->toThreadCond);
|
|
|
|
MutexDeinit(&proxyRenderer->mutex);
|
|
|
|
proxyRenderer->backend->deinit(proxyRenderer->backend);
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererDeinit(&proxyRenderer->proxy);
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 05:17:20 +00:00
|
|
|
void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2016-08-18 07:08:04 +00:00
|
|
|
if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) {
|
2016-08-18 05:17:20 +00:00
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
RingFIFOClear(&proxyRenderer->dirtyQueue);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
ThreadJoin(proxyRenderer->thread);
|
|
|
|
proxyRenderer->threadState = PROXY_THREAD_IDLE;
|
|
|
|
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
|
|
|
}
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
static bool _writeData(struct mVideoProxy* proxy, void* data, size_t length) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
2016-08-15 02:40:24 +00:00
|
|
|
while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) {
|
2016-09-17 11:34:02 +00:00
|
|
|
mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);
|
2016-08-15 02:40:24 +00:00
|
|
|
MutexLock(&proxyRenderer->mutex);
|
|
|
|
if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) {
|
|
|
|
mLOG(GBA_VIDEO, ERROR, "Proxy thread stopped prematurely!");
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
|
|
|
return &proxyRenderer->d.vram[address >> 1];
|
|
|
|
}
|
|
|
|
|
2015-07-29 06:56:45 +00:00
|
|
|
uint16_t GBAVideoThreadProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
switch (address) {
|
|
|
|
case REG_BG0CNT:
|
|
|
|
case REG_BG1CNT:
|
|
|
|
case REG_BG2CNT:
|
|
|
|
case REG_BG3CNT:
|
|
|
|
value &= 0xFFCF;
|
|
|
|
break;
|
|
|
|
case REG_BG0HOFS:
|
|
|
|
case REG_BG0VOFS:
|
|
|
|
case REG_BG1HOFS:
|
|
|
|
case REG_BG1VOFS:
|
|
|
|
case REG_BG2HOFS:
|
|
|
|
case REG_BG2VOFS:
|
|
|
|
case REG_BG3HOFS:
|
|
|
|
case REG_BG3VOFS:
|
|
|
|
value &= 0x01FF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (address > REG_BLDY) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererWriteVideoRegister(&proxyRenderer->proxy, address, value);
|
2015-07-29 06:56:45 +00:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererWriteVRAM(&proxyRenderer->proxy, address);
|
2016-10-17 18:59:31 +00:00
|
|
|
if (renderer->cache) {
|
|
|
|
mTileCacheWriteVRAM(renderer->cache, address);
|
|
|
|
}
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererWritePalette(&proxyRenderer->proxy, address, value);
|
2016-08-10 06:34:36 +00:00
|
|
|
if (renderer->cache) {
|
2016-10-17 18:59:31 +00:00
|
|
|
mTileCacheWritePalette(renderer->cache, address);
|
2016-08-10 06:34:36 +00:00
|
|
|
}
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererWriteOAM(&proxyRenderer->proxy, oam, proxyRenderer->d.oam->raw[oam]);
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererDrawScanline(&proxyRenderer->proxy, y);
|
2016-08-06 05:40:02 +00:00
|
|
|
if ((y & 15) == 15) {
|
2015-10-16 06:13:45 +00:00
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
}
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GBAVideoThreadProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
2016-08-14 11:20:37 +00:00
|
|
|
if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) {
|
2016-08-15 02:40:24 +00:00
|
|
|
mLOG(GBA_VIDEO, ERROR, "Proxy thread stopped prematurely!");
|
2016-08-18 05:17:20 +00:00
|
|
|
_proxyThreadRecover(proxyRenderer);
|
2016-08-14 11:20:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-07-29 06:56:45 +00:00
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2015-07-29 08:04:23 +00:00
|
|
|
// Insert an extra item into the queue to make sure it gets flushed
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererFlush(&proxyRenderer->proxy);
|
2016-08-10 05:30:35 +00:00
|
|
|
do {
|
2015-07-29 06:56:45 +00:00
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
2016-08-10 05:30:35 +00:00
|
|
|
} while (proxyRenderer->threadState == PROXY_THREAD_BUSY);
|
2015-07-29 06:56:45 +00:00
|
|
|
proxyRenderer->backend->finishFrame(proxyRenderer->backend);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
|
2016-09-17 10:37:04 +00:00
|
|
|
static void GBAVideoThreadProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
|
2016-08-15 02:40:24 +00:00
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2016-08-06 17:28:30 +00:00
|
|
|
// Insert an extra item into the queue to make sure it gets flushed
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererFlush(&proxyRenderer->proxy);
|
2016-08-06 17:28:30 +00:00
|
|
|
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
2016-09-17 10:37:04 +00:00
|
|
|
static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
|
2016-08-15 02:40:24 +00:00
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2016-08-06 17:28:30 +00:00
|
|
|
// Insert an extra item into the queue to make sure it gets flushed
|
2017-04-14 00:15:16 +00:00
|
|
|
mVideoProxyRendererFlush(&proxyRenderer->proxy);
|
2016-08-06 17:28:30 +00:00
|
|
|
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
|
|
|
ConditionWake(&proxyRenderer->toThreadCond);
|
|
|
|
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
|
|
}
|
|
|
|
proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static THREAD_ENTRY _proxyThread(void* renderer) {
|
|
|
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = renderer;
|
|
|
|
ThreadSetName("Proxy Renderer Thread");
|
|
|
|
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2017-04-14 00:15:16 +00:00
|
|
|
struct mVideoProxyDirtyInfo item = {0};
|
2016-08-02 02:09:46 +00:00
|
|
|
while (proxyRenderer->threadState != PROXY_THREAD_STOPPED) {
|
2015-07-29 06:56:45 +00:00
|
|
|
ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex);
|
|
|
|
if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) {
|
|
|
|
break;
|
|
|
|
}
|
2016-08-10 05:30:35 +00:00
|
|
|
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:
|
2017-04-14 00:15:16 +00:00
|
|
|
proxyRenderer->proxy.palette[item.address >> 1] = item.value;
|
2016-08-10 05:30:35 +00:00
|
|
|
proxyRenderer->backend->writePalette(proxyRenderer->backend, item.address, item.value);
|
|
|
|
break;
|
|
|
|
case DIRTY_OAM:
|
2017-04-14 00:15:16 +00:00
|
|
|
proxyRenderer->proxy.oam[item.address] = item.value;
|
2016-08-10 05:30:35 +00:00
|
|
|
proxyRenderer->backend->writeOAM(proxyRenderer->backend, item.address);
|
|
|
|
break;
|
|
|
|
case DIRTY_VRAM:
|
2017-04-14 00:15:16 +00:00
|
|
|
while (!RingFIFORead(&proxyRenderer->dirtyQueue, &proxyRenderer->proxy.vram[item.address >> 1], 0x1000)) {
|
2016-09-17 11:34:02 +00:00
|
|
|
mLOG(GBA_VIDEO, DEBUG, "Proxy thread can't read VRAM. CPU thread asleep?");
|
2016-08-15 02:40:24 +00:00
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2016-08-14 11:20:37 +00:00
|
|
|
ConditionWake(&proxyRenderer->fromThreadCond);
|
2016-08-15 02:40:24 +00:00
|
|
|
ConditionWait(&proxyRenderer->toThreadCond, &proxyRenderer->mutex);
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
2016-08-14 11:20:37 +00:00
|
|
|
}
|
2016-08-10 05:30:35 +00:00
|
|
|
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;
|
2016-08-15 02:40:24 +00:00
|
|
|
mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!");
|
2016-08-10 05:30:35 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} while (proxyRenderer->threadState == PROXY_THREAD_BUSY && RingFIFORead(&proxyRenderer->dirtyQueue, &item, sizeof(item)));
|
|
|
|
MutexLock(&proxyRenderer->mutex);
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
2016-08-10 05:30:35 +00:00
|
|
|
out:
|
2015-07-29 06:56:45 +00:00
|
|
|
ConditionWake(&proxyRenderer->fromThreadCond);
|
2015-09-04 08:48:24 +00:00
|
|
|
if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) {
|
|
|
|
proxyRenderer->threadState = PROXY_THREAD_IDLE;
|
|
|
|
}
|
2015-07-29 06:56:45 +00:00
|
|
|
}
|
|
|
|
MutexUnlock(&proxyRenderer->mutex);
|
|
|
|
|
2015-09-04 08:48:24 +00:00
|
|
|
#ifdef _3DS
|
|
|
|
svcExitThread();
|
|
|
|
#endif
|
2015-07-29 06:56:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2015-08-30 03:08:00 +00:00
|
|
|
|
|
|
|
#endif
|