all repos — mgba @ bed6ba1fc48a7432c8b45ebb38ea7e403c45bfb0

mGBA Game Boy Advance Emulator

GBA Video: Refactor thread proxy out from proxy
Vicki Pfau vi@endrift.com
Fri, 14 Apr 2017 14:05:29 -0700
commit

bed6ba1fc48a7432c8b45ebb38ea7e403c45bfb0

parent

eab5ed6e142e75656adbe918f2422d936f67c5c2

A include/mgba/core/video-logger.h

@@ -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
D include/mgba/core/video-proxy.h

@@ -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
A include/mgba/internal/gba/renderers/proxy.h

@@ -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
M include/mgba/internal/gba/renderers/thread-proxy.hinclude/mgba/internal/gba/renderers/thread-proxy.h

@@ -10,8 +10,8 @@ #include <mgba-util/common.h>

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 @@ PROXY_THREAD_BUSY

}; struct GBAVideoThreadProxyRenderer { - struct GBAVideoRenderer d; - struct GBAVideoRenderer* backend; - struct mVideoProxy proxy; + struct GBAVideoProxyRenderer d; Thread thread; Condition fromThreadCond;
A src/core/video-logger.c

@@ -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; +}
D src/core/video-proxy.c

@@ -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; -}
M src/gba/core.csrc/gba/core.c

@@ -290,7 +290,7 @@ if (gbacore->renderer.outputBuffer) {

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);
A src/gba/renderers/proxy.c

@@ -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); + } +}
M src/gba/renderers/thread-proxy.csrc/gba/renderers/thread-proxy.c

@@ -9,98 +9,60 @@ #include <mgba/core/tile-cache.h>

#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 @@ }

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 @@ proxyRenderer->threadState = PROXY_THREAD_IDLE;

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 @@ }

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 @@ }

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]; -} - -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); - } +static void _lock(struct GBAVideoProxyRenderer* proxyRenderer) { + struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer; + MutexLock(&threadProxy->mutex); } -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 @@ break;

} 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!");