GBA Video: Refactor thread proxy out from proxy

This commit is contained in:
Vicki Pfau 2017-04-14 14:05:29 -07:00
parent eab5ed6e14
commit bed6ba1fc4
9 changed files with 526 additions and 398 deletions

View File

@ -0,0 +1,66 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef VIDEO_LOGGER_H
#define VIDEO_LOGGER_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum mVideoLoggerDirtyType {
DIRTY_DUMMY = 0,
DIRTY_FLUSH,
DIRTY_SCANLINE,
DIRTY_REGISTER,
DIRTY_OAM,
DIRTY_PALETTE,
DIRTY_VRAM
};
struct mVideoLoggerDirtyInfo {
enum mVideoLoggerDirtyType type;
uint32_t address;
uint16_t value;
uint32_t padding;
};
struct mVideoLogger {
bool (*writeData)(struct mVideoLogger* logger, const void* data, size_t length);
bool (*readData)(struct mVideoLogger* logger, void* data, size_t length, bool block);
void* context;
bool (*parsePacket)(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet);
uint16_t* (*vramBlock)(struct mVideoLogger* logger, uint32_t address);
size_t vramSize;
size_t oamSize;
size_t paletteSize;
uint32_t* vramDirtyBitmap;
uint32_t* oamDirtyBitmap;
uint16_t* vram;
uint16_t* oam;
uint16_t* palette;
};
void mVideoLoggerRendererInit(struct mVideoLogger* logger);
void mVideoLoggerRendererDeinit(struct mVideoLogger* logger);
void mVideoLoggerRendererReset(struct mVideoLogger* logger);
void mVideoLoggerRendererWriteVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value);
void mVideoLoggerRendererWriteVRAM(struct mVideoLogger* logger, uint32_t address);
void mVideoLoggerRendererWritePalette(struct mVideoLogger* logger, uint32_t address, uint16_t value);
void mVideoLoggerRendererWriteOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value);
void mVideoLoggerRendererDrawScanline(struct mVideoLogger* logger, int y);
void mVideoLoggerRendererFlush(struct mVideoLogger* logger);
bool mVideoLoggerRendererRun(struct mVideoLogger* logger);
CXX_GUARD_END
#endif

View File

@ -1,66 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef VIDEO_PROXY_H
#define VIDEO_PROXY_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum mVideoProxyDirtyType {
DIRTY_DUMMY = 0,
DIRTY_FLUSH,
DIRTY_SCANLINE,
DIRTY_REGISTER,
DIRTY_OAM,
DIRTY_PALETTE,
DIRTY_VRAM
};
struct mVideoProxyDirtyInfo {
enum mVideoProxyDirtyType type;
uint32_t address;
uint16_t value;
uint32_t padding;
};
struct mVideoProxy {
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);
size_t vramSize;
size_t oamSize;
size_t paletteSize;
uint32_t* vramDirtyBitmap;
uint32_t* oamDirtyBitmap;
uint16_t* vram;
uint16_t* oam;
uint16_t* palette;
};
void mVideoProxyRendererInit(struct mVideoProxy* proxy);
void mVideoProxyRendererDeinit(struct mVideoProxy* proxy);
void mVideoProxyRendererReset(struct mVideoProxy* proxy);
void mVideoProxyRendererWriteVideoRegister(struct mVideoProxy* proxy, uint32_t address, uint16_t value);
void mVideoProxyRendererWriteVRAM(struct mVideoProxy* proxy, uint32_t address);
void mVideoProxyRendererWritePalette(struct mVideoProxy* proxy, uint32_t address, uint16_t value);
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
#endif

View File

@ -0,0 +1,37 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GBA_VIDEO_PROXY_H
#define GBA_VIDEO_PROXY_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/internal/gba/video.h>
#include <mgba/core/video-logger.h>
struct GBAVideoProxyRenderer {
struct GBAVideoRenderer d;
struct GBAVideoRenderer* backend;
struct mVideoLogger logger;
bool block;
void (*init)(struct GBAVideoProxyRenderer*);
void (*deinit)(struct GBAVideoProxyRenderer*);
void (*reset)(struct GBAVideoProxyRenderer*);
void (*lock)(struct GBAVideoProxyRenderer*);
void (*unlock)(struct GBAVideoProxyRenderer*);
void (*wait)(struct GBAVideoProxyRenderer*);
void (*wake)(struct GBAVideoProxyRenderer*, int y);
};
void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend);
CXX_GUARD_END
#endif

View File

@ -10,8 +10,8 @@
CXX_GUARD_START
#include <mgba/core/video-proxy.h>
#include <mgba/internal/gba/video.h>
#include <mgba/internal/gba/renderers/proxy.h>
#include <mgba-util/threading.h>
#include <mgba-util/ring-fifo.h>
@ -22,9 +22,7 @@ enum GBAVideoThreadProxyState {
};
struct GBAVideoThreadProxyRenderer {
struct GBAVideoRenderer d;
struct GBAVideoRenderer* backend;
struct mVideoProxy proxy;
struct GBAVideoProxyRenderer d;
Thread thread;
Condition fromThreadCond;

136
src/core/video-logger.c Normal file
View File

@ -0,0 +1,136 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/video-logger.h>
#include <mgba-util/memory.h>
static inline size_t _roundUp(size_t value, int shift) {
value += (1 << shift) - 1;
return value >> shift;
}
void mVideoLoggerRendererInit(struct mVideoLogger* logger) {
logger->palette = anonymousMemoryMap(logger->paletteSize);
logger->vram = anonymousMemoryMap(logger->vramSize);
logger->oam = anonymousMemoryMap(logger->oamSize);
logger->vramDirtyBitmap = calloc(_roundUp(logger->vramSize, 17), sizeof(uint32_t));
logger->oamDirtyBitmap = calloc(_roundUp(logger->oamSize, 6), sizeof(uint32_t));
}
void mVideoLoggerRendererDeinit(struct mVideoLogger* logger) {
mappedMemoryFree(logger->palette, logger->paletteSize);
mappedMemoryFree(logger->vram, logger->vramSize);
mappedMemoryFree(logger->oam, logger->oamSize);
free(logger->vramDirtyBitmap);
free(logger->oamDirtyBitmap);
}
void mVideoLoggerRendererReset(struct mVideoLogger* logger) {
memset(logger->vramDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(logger->vramSize, 17));
memset(logger->oamDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(logger->oamSize, 6));
}
void mVideoLoggerRendererWriteVideoRegister(struct mVideoLogger* logger, uint32_t address, uint16_t value) {
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_REGISTER,
address,
value,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
}
void mVideoLoggerRendererWriteVRAM(struct mVideoLogger* logger, uint32_t address) {
int bit = 1 << (address >> 12);
if (logger->vramDirtyBitmap[address >> 17] & bit) {
return;
}
logger->vramDirtyBitmap[address >> 17] |= bit;
}
void mVideoLoggerRendererWritePalette(struct mVideoLogger* logger, uint32_t address, uint16_t value) {
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_PALETTE,
address,
value,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
}
void mVideoLoggerRendererWriteOAM(struct mVideoLogger* logger, uint32_t address, uint16_t value) {
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_OAM,
address,
value,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
}
void mVideoLoggerRendererDrawScanline(struct mVideoLogger* logger, int y) {
size_t i;
for (i = 0; i < _roundUp(logger->vramSize, 17); ++i) {
if (logger->vramDirtyBitmap[i]) {
uint32_t bitmap = logger->vramDirtyBitmap[i];
logger->vramDirtyBitmap[i] = 0;
int j;
for (j = 0; j < 32; ++j) {
if (!(bitmap & (1 << j))) {
continue;
}
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_VRAM,
j * 0x1000,
0xABCD,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
logger->writeData(logger, logger->vramBlock(logger, j * 0x1000), 0x1000);
}
}
}
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_SCANLINE,
y,
0,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
}
void mVideoLoggerRendererFlush(struct mVideoLogger* logger) {
struct mVideoLoggerDirtyInfo dirty = {
DIRTY_FLUSH,
0,
0,
0xDEADBEEF,
};
logger->writeData(logger, &dirty, sizeof(dirty));
}
bool mVideoLoggerRendererRun(struct mVideoLogger* logger) {
struct mVideoLoggerDirtyInfo item = {0};
while (logger->readData(logger, &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 (!logger->parsePacket(logger, &item)) {
return true;
}
break;
default:
return false;
}
}
return true;
}

View File

@ -1,136 +0,0 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/video-proxy.h>
#include <mgba-util/memory.h>
static inline size_t _roundUp(size_t value, int shift) {
value += (1 << shift) - 1;
return value >> shift;
}
void mVideoProxyRendererInit(struct mVideoProxy* proxy) {
proxy->palette = anonymousMemoryMap(proxy->paletteSize);
proxy->vram = anonymousMemoryMap(proxy->vramSize);
proxy->oam = anonymousMemoryMap(proxy->oamSize);
proxy->vramDirtyBitmap = calloc(_roundUp(proxy->vramSize, 17), sizeof(uint32_t));
proxy->oamDirtyBitmap = calloc(_roundUp(proxy->oamSize, 6), sizeof(uint32_t));
}
void mVideoProxyRendererDeinit(struct mVideoProxy* proxy) {
mappedMemoryFree(proxy->palette, proxy->paletteSize);
mappedMemoryFree(proxy->vram, proxy->vramSize);
mappedMemoryFree(proxy->oam, proxy->oamSize);
free(proxy->vramDirtyBitmap);
free(proxy->oamDirtyBitmap);
}
void mVideoProxyRendererReset(struct mVideoProxy* proxy) {
memset(proxy->vramDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(proxy->vramSize, 17));
memset(proxy->oamDirtyBitmap, 0, sizeof(uint32_t) * _roundUp(proxy->oamSize, 6));
}
void mVideoProxyRendererWriteVideoRegister(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
struct mVideoProxyDirtyInfo dirty = {
DIRTY_REGISTER,
address,
value,
0xDEADBEEF,
};
proxy->writeData(proxy, &dirty, sizeof(dirty));
}
void mVideoProxyRendererWriteVRAM(struct mVideoProxy* proxy, uint32_t address) {
int bit = 1 << (address >> 12);
if (proxy->vramDirtyBitmap[address >> 17] & bit) {
return;
}
proxy->vramDirtyBitmap[address >> 17] |= bit;
}
void mVideoProxyRendererWritePalette(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
struct mVideoProxyDirtyInfo dirty = {
DIRTY_PALETTE,
address,
value,
0xDEADBEEF,
};
proxy->writeData(proxy, &dirty, sizeof(dirty));
}
void mVideoProxyRendererWriteOAM(struct mVideoProxy* proxy, uint32_t address, uint16_t value) {
struct mVideoProxyDirtyInfo dirty = {
DIRTY_OAM,
address,
value,
0xDEADBEEF,
};
proxy->writeData(proxy, &dirty, sizeof(dirty));
}
void mVideoProxyRendererDrawScanline(struct mVideoProxy* proxy, int y) {
size_t i;
for (i = 0; i < _roundUp(proxy->vramSize, 17); ++i) {
if (proxy->vramDirtyBitmap[i]) {
uint32_t bitmap = proxy->vramDirtyBitmap[i];
proxy->vramDirtyBitmap[i] = 0;
int j;
for (j = 0; j < 32; ++j) {
if (!(bitmap & (1 << j))) {
continue;
}
struct mVideoProxyDirtyInfo dirty = {
DIRTY_VRAM,
j * 0x1000,
0xABCD,
0xDEADBEEF,
};
proxy->writeData(proxy, &dirty, sizeof(dirty));
proxy->writeData(proxy, proxy->vramBlock(proxy, j * 0x1000), 0x1000);
}
}
}
struct mVideoProxyDirtyInfo dirty = {
DIRTY_SCANLINE,
y,
0,
0xDEADBEEF,
};
proxy->writeData(proxy, &dirty, sizeof(dirty));
}
void mVideoProxyRendererFlush(struct mVideoProxy* proxy) {
struct mVideoProxyDirtyInfo dirty = {
DIRTY_FLUSH,
0,
0,
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;
}

View File

@ -290,7 +290,7 @@ static void _GBACoreReset(struct mCore* core) {
struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
#ifndef DISABLE_THREADING
if (gbacore->threadedVideo) {
renderer = &gbacore->threadProxy.d;
renderer = &gbacore->threadProxy.d.d;
}
#endif
GBAVideoAssociateRenderer(&gba->video, renderer);

239
src/gba/renderers/proxy.c Normal file
View File

@ -0,0 +1,239 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gba/renderers/proxy.h>
#include <mgba/core/tile-cache.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
static void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer);
static void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer);
static uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
static void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
static void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
static void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer);
static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet);
static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address);
void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
renderer->d.init = GBAVideoProxyRendererInit;
renderer->d.reset = GBAVideoProxyRendererReset;
renderer->d.deinit = GBAVideoProxyRendererDeinit;
renderer->d.writeVideoRegister = GBAVideoProxyRendererWriteVideoRegister;
renderer->d.writeVRAM = GBAVideoProxyRendererWriteVRAM;
renderer->d.writeOAM = GBAVideoProxyRendererWriteOAM;
renderer->d.writePalette = GBAVideoProxyRendererWritePalette;
renderer->d.drawScanline = GBAVideoProxyRendererDrawScanline;
renderer->d.finishFrame = GBAVideoProxyRendererFinishFrame;
renderer->d.getPixels = GBAVideoProxyRendererGetPixels;
renderer->d.putPixels = GBAVideoProxyRendererPutPixels;
renderer->d.disableBG[0] = false;
renderer->d.disableBG[1] = false;
renderer->d.disableBG[2] = false;
renderer->d.disableBG[3] = false;
renderer->d.disableOBJ = false;
renderer->logger.context = renderer;
renderer->logger.writeData = NULL;
renderer->logger.readData = NULL;
renderer->logger.parsePacket = _parsePacket;
renderer->logger.vramBlock = _vramBlock;
renderer->logger.paletteSize = SIZE_PALETTE_RAM;
renderer->logger.vramSize = SIZE_VRAM;
renderer->logger.oamSize = SIZE_OAM;
renderer->backend = backend;
}
void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
mVideoLoggerRendererInit(&proxyRenderer->logger);
if (proxyRenderer->block) {
proxyRenderer->backend->palette = proxyRenderer->logger.palette;
proxyRenderer->backend->vram = proxyRenderer->logger.vram;
proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->logger.oam;
proxyRenderer->backend->cache = NULL;
}
proxyRenderer->init(proxyRenderer);
proxyRenderer->backend->init(proxyRenderer->backend);
}
void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
memcpy(proxyRenderer->logger.oam, &renderer->oam->raw, SIZE_OAM);
memcpy(proxyRenderer->logger.palette, renderer->palette, SIZE_PALETTE_RAM);
memcpy(proxyRenderer->logger.vram, renderer->vram, SIZE_VRAM);
mVideoLoggerRendererReset(&proxyRenderer->logger);
proxyRenderer->reset(proxyRenderer);
proxyRenderer->backend->reset(proxyRenderer->backend);
}
void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
proxyRenderer->deinit(proxyRenderer);
proxyRenderer->backend->deinit(proxyRenderer->backend);
mVideoLoggerRendererDeinit(&proxyRenderer->logger);
}
static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
switch (item->type) {
case DIRTY_REGISTER:
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
break;
case DIRTY_PALETTE:
logger->palette[item->address >> 1] = item->value;
proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
break;
case DIRTY_OAM:
logger->oam[item->address] = item->value;
proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
break;
case DIRTY_VRAM:
logger->readData(logger, &logger->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 mVideoLogger* logger, uint32_t address) {
struct GBAVideoProxyRenderer* proxyRenderer = logger->context;
return &proxyRenderer->d.vram[address >> 1];
}
uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) 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;
}
mVideoLoggerRendererWriteVideoRegister(&proxyRenderer->logger, address, value);
return value;
}
void GBAVideoProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
mVideoLoggerRendererWriteVRAM(&proxyRenderer->logger, address);
if (!proxyRenderer->block) {
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
}
if (renderer->cache) {
mTileCacheWriteVRAM(renderer->cache, address);
}
}
void GBAVideoProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
mVideoLoggerRendererWritePalette(&proxyRenderer->logger, address, value);
if (!proxyRenderer->block) {
proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
}
if (renderer->cache) {
mTileCacheWritePalette(renderer->cache, address);
}
}
void GBAVideoProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (!proxyRenderer->block) {
proxyRenderer->backend->writeOAM(proxyRenderer->backend, oam);
}
mVideoLoggerRendererWriteOAM(&proxyRenderer->logger, oam, proxyRenderer->d.oam->raw[oam]);
}
void GBAVideoProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (!proxyRenderer->block) {
proxyRenderer->backend->drawScanline(proxyRenderer->backend, y);
}
mVideoLoggerRendererDrawScanline(&proxyRenderer->logger, y);
if (proxyRenderer->block) {
proxyRenderer->wake(proxyRenderer, y);
}
}
void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (proxyRenderer->block) {
proxyRenderer->lock(proxyRenderer);
proxyRenderer->wait(proxyRenderer);
}
mVideoLoggerRendererFlush(&proxyRenderer->logger);
if (proxyRenderer->block) {
proxyRenderer->unlock(proxyRenderer);
}
}
static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (proxyRenderer->block) {
proxyRenderer->lock(proxyRenderer);
// Insert an extra item into the queue to make sure it gets flushed
mVideoLoggerRendererFlush(&proxyRenderer->logger);
proxyRenderer->wait(proxyRenderer);
}
proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
if (proxyRenderer->block) {
proxyRenderer->unlock(proxyRenderer);
}
}
static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer;
if (proxyRenderer->block) {
proxyRenderer->lock(proxyRenderer);
// Insert an extra item into the queue to make sure it gets flushed
mVideoLoggerRendererFlush(&proxyRenderer->logger);
proxyRenderer->wait(proxyRenderer);
}
proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
if (proxyRenderer->block) {
proxyRenderer->unlock(proxyRenderer);
}
}

View File

@ -9,98 +9,60 @@
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h>
#include <mgba-util/memory.h>
#ifndef DISABLE_THREADING
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);
static void GBAVideoThreadProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
static void GBAVideoThreadProxyRendererInit(struct GBAVideoProxyRenderer* renderer);
static void GBAVideoThreadProxyRendererReset(struct GBAVideoProxyRenderer* renderer);
static void GBAVideoThreadProxyRendererDeinit(struct GBAVideoProxyRenderer* renderer);
static THREAD_ENTRY _proxyThread(void* renderer);
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 bool _writeData(struct mVideoLogger* logger, const void* data, size_t length);
static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bool block);
static void _lock(struct GBAVideoProxyRenderer* proxyRenderer);
static void _unlock(struct GBAVideoProxyRenderer* proxyRenderer);
static void _wait(struct GBAVideoProxyRenderer* proxyRenderer);
static void _wake(struct GBAVideoProxyRenderer* proxyRenderer, int y);
void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
renderer->d.block = true;
GBAVideoProxyRendererCreate(&renderer->d, 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.lock = _lock;
renderer->d.unlock = _unlock;
renderer->d.wait = _wait;
renderer->d.wake = _wake;
renderer->d.disableBG[0] = false;
renderer->d.disableBG[1] = false;
renderer->d.disableBG[2] = false;
renderer->d.disableBG[3] = false;
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;
renderer->proxy.oamSize = SIZE_OAM;
renderer->backend = backend;
renderer->d.logger.writeData = _writeData;
renderer->d.logger.readData = _readData;
}
void GBAVideoThreadProxyRendererInit(struct GBAVideoRenderer* renderer) {
void GBAVideoThreadProxyRendererInit(struct GBAVideoProxyRenderer* renderer) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
ConditionInit(&proxyRenderer->fromThreadCond);
ConditionInit(&proxyRenderer->toThreadCond);
MutexInit(&proxyRenderer->mutex);
RingFIFOInit(&proxyRenderer->dirtyQueue, 0x40000);
mVideoProxyRendererInit(&proxyRenderer->proxy);
proxyRenderer->backend->palette = proxyRenderer->proxy.palette;
proxyRenderer->backend->vram = proxyRenderer->proxy.vram;
proxyRenderer->backend->oam = (union GBAOAM*) proxyRenderer->proxy.oam;
proxyRenderer->backend->cache = NULL;
proxyRenderer->backend->init(proxyRenderer->backend);
proxyRenderer->threadState = PROXY_THREAD_IDLE;
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
}
void GBAVideoThreadProxyRendererReset(struct GBAVideoRenderer* renderer) {
void GBAVideoThreadProxyRendererReset(struct GBAVideoProxyRenderer* renderer) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
MutexLock(&proxyRenderer->mutex);
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
ConditionWake(&proxyRenderer->toThreadCond);
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
}
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);
proxyRenderer->backend->reset(proxyRenderer->backend);
MutexUnlock(&proxyRenderer->mutex);
}
void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
void GBAVideoThreadProxyRendererDeinit(struct GBAVideoProxyRenderer* renderer) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
bool waiting = false;
MutexLock(&proxyRenderer->mutex);
@ -120,9 +82,6 @@ void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
ConditionDeinit(&proxyRenderer->fromThreadCond);
ConditionDeinit(&proxyRenderer->toThreadCond);
MutexDeinit(&proxyRenderer->mutex);
proxyRenderer->backend->deinit(proxyRenderer->backend);
mVideoProxyRendererDeinit(&proxyRenderer->proxy);
}
void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
@ -138,8 +97,8 @@ void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
}
static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t length) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = logger->context;
while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) {
mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);
MutexLock(&proxyRenderer->mutex);
@ -155,8 +114,8 @@ static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t lengt
return true;
}
static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool block) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bool block) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = logger->context;
bool read = false;
while (true) {
read = RingFIFORead(&proxyRenderer->dirtyQueue, data, length);
@ -172,139 +131,34 @@ static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool
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 void _lock(struct GBAVideoProxyRenderer* proxyRenderer) {
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
MutexLock(&threadProxy->mutex);
}
static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
return &proxyRenderer->d.vram[address >> 1];
}
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;
}
mVideoProxyRendererWriteVideoRegister(&proxyRenderer->proxy, address, value);
return value;
}
void GBAVideoThreadProxyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
mVideoProxyRendererWriteVRAM(&proxyRenderer->proxy, address);
if (renderer->cache) {
mTileCacheWriteVRAM(renderer->cache, address);
}
}
void GBAVideoThreadProxyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
mVideoProxyRendererWritePalette(&proxyRenderer->proxy, address, value);
if (renderer->cache) {
mTileCacheWritePalette(renderer->cache, address);
}
}
void GBAVideoThreadProxyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
mVideoProxyRendererWriteOAM(&proxyRenderer->proxy, oam, proxyRenderer->d.oam->raw[oam]);
}
void GBAVideoThreadProxyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
mVideoProxyRendererDrawScanline(&proxyRenderer->proxy, y);
if ((y & 15) == 15) {
ConditionWake(&proxyRenderer->toThreadCond);
}
}
void GBAVideoThreadProxyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
if (proxyRenderer->threadState == PROXY_THREAD_STOPPED) {
static void _wait(struct GBAVideoProxyRenderer* proxyRenderer) {
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
if (threadProxy->threadState == PROXY_THREAD_STOPPED) {
mLOG(GBA_VIDEO, ERROR, "Proxy thread stopped prematurely!");
_proxyThreadRecover(proxyRenderer);
_proxyThreadRecover(threadProxy);
return;
}
MutexLock(&proxyRenderer->mutex);
// Insert an extra item into the queue to make sure it gets flushed
mVideoProxyRendererFlush(&proxyRenderer->proxy);
do {
ConditionWake(&proxyRenderer->toThreadCond);
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
} while (proxyRenderer->threadState == PROXY_THREAD_BUSY);
proxyRenderer->backend->finishFrame(proxyRenderer->backend);
MutexUnlock(&proxyRenderer->mutex);
while (threadProxy->threadState == PROXY_THREAD_BUSY) {
ConditionWake(&threadProxy->toThreadCond);
ConditionWait(&threadProxy->fromThreadCond, &threadProxy->mutex);
}
}
static void GBAVideoThreadProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
MutexLock(&proxyRenderer->mutex);
// Insert an extra item into the queue to make sure it gets flushed
mVideoProxyRendererFlush(&proxyRenderer->proxy);
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
ConditionWake(&proxyRenderer->toThreadCond);
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
}
proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
MutexUnlock(&proxyRenderer->mutex);
static void _unlock(struct GBAVideoProxyRenderer* proxyRenderer) {
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
MutexUnlock(&threadProxy->mutex);
}
static void GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
MutexLock(&proxyRenderer->mutex);
// Insert an extra item into the queue to make sure it gets flushed
mVideoProxyRendererFlush(&proxyRenderer->proxy);
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
ConditionWake(&proxyRenderer->toThreadCond);
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
static void _wake(struct GBAVideoProxyRenderer* proxyRenderer, int y) {
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
if ((y & 15) == 15) {
ConditionWake(&threadProxy->toThreadCond);
}
proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
MutexUnlock(&proxyRenderer->mutex);
}
static THREAD_ENTRY _proxyThread(void* renderer) {
@ -319,7 +173,7 @@ static THREAD_ENTRY _proxyThread(void* renderer) {
}
proxyRenderer->threadState = PROXY_THREAD_BUSY;
MutexUnlock(&proxyRenderer->mutex);
if (!mVideoProxyRendererRun(&proxyRenderer->proxy)) {
if (!mVideoLoggerRendererRun(&proxyRenderer->d.logger)) {
// FIFO was corrupted
proxyRenderer->threadState = PROXY_THREAD_STOPPED;
mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!");