mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Refactor thread proxy out from proxy
This commit is contained in:
parent
eab5ed6e14
commit
bed6ba1fc4
|
@ -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
|
|
@ -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
|
|
|
@ -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
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
CXX_GUARD_START
|
CXX_GUARD_START
|
||||||
|
|
||||||
#include <mgba/core/video-proxy.h>
|
|
||||||
#include <mgba/internal/gba/video.h>
|
#include <mgba/internal/gba/video.h>
|
||||||
|
#include <mgba/internal/gba/renderers/proxy.h>
|
||||||
#include <mgba-util/threading.h>
|
#include <mgba-util/threading.h>
|
||||||
#include <mgba-util/ring-fifo.h>
|
#include <mgba-util/ring-fifo.h>
|
||||||
|
|
||||||
|
@ -22,9 +22,7 @@ enum GBAVideoThreadProxyState {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBAVideoThreadProxyRenderer {
|
struct GBAVideoThreadProxyRenderer {
|
||||||
struct GBAVideoRenderer d;
|
struct GBAVideoProxyRenderer d;
|
||||||
struct GBAVideoRenderer* backend;
|
|
||||||
struct mVideoProxy proxy;
|
|
||||||
|
|
||||||
Thread thread;
|
Thread thread;
|
||||||
Condition fromThreadCond;
|
Condition fromThreadCond;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -290,7 +290,7 @@ static void _GBACoreReset(struct mCore* core) {
|
||||||
struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
|
struct GBAVideoRenderer* renderer = &gbacore->renderer.d;
|
||||||
#ifndef DISABLE_THREADING
|
#ifndef DISABLE_THREADING
|
||||||
if (gbacore->threadedVideo) {
|
if (gbacore->threadedVideo) {
|
||||||
renderer = &gbacore->threadProxy.d;
|
renderer = &gbacore->threadProxy.d.d;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
GBAVideoAssociateRenderer(&gba->video, renderer);
|
GBAVideoAssociateRenderer(&gba->video, renderer);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,98 +9,60 @@
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
#include <mgba/internal/gba/io.h>
|
#include <mgba/internal/gba/io.h>
|
||||||
|
|
||||||
#include <mgba-util/memory.h>
|
|
||||||
|
|
||||||
#ifndef DISABLE_THREADING
|
#ifndef DISABLE_THREADING
|
||||||
|
|
||||||
static void GBAVideoThreadProxyRendererInit(struct GBAVideoRenderer* renderer);
|
static void GBAVideoThreadProxyRendererInit(struct GBAVideoProxyRenderer* renderer);
|
||||||
static void GBAVideoThreadProxyRendererReset(struct GBAVideoRenderer* renderer);
|
static void GBAVideoThreadProxyRendererReset(struct GBAVideoProxyRenderer* renderer);
|
||||||
static void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer);
|
static void GBAVideoThreadProxyRendererDeinit(struct GBAVideoProxyRenderer* 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 THREAD_ENTRY _proxyThread(void* renderer);
|
static THREAD_ENTRY _proxyThread(void* renderer);
|
||||||
|
|
||||||
static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t length);
|
static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length);
|
||||||
static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool block);
|
static bool _readData(struct mVideoLogger* logger, 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 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) {
|
void GBAVideoThreadProxyRendererCreate(struct GBAVideoThreadProxyRenderer* renderer, struct GBAVideoRenderer* backend) {
|
||||||
|
renderer->d.block = true;
|
||||||
|
GBAVideoProxyRendererCreate(&renderer->d, backend);
|
||||||
|
|
||||||
renderer->d.init = GBAVideoThreadProxyRendererInit;
|
renderer->d.init = GBAVideoThreadProxyRendererInit;
|
||||||
renderer->d.reset = GBAVideoThreadProxyRendererReset;
|
renderer->d.reset = GBAVideoThreadProxyRendererReset;
|
||||||
renderer->d.deinit = GBAVideoThreadProxyRendererDeinit;
|
renderer->d.deinit = GBAVideoThreadProxyRendererDeinit;
|
||||||
renderer->d.writeVideoRegister = GBAVideoThreadProxyRendererWriteVideoRegister;
|
renderer->d.lock = _lock;
|
||||||
renderer->d.writeVRAM = GBAVideoThreadProxyRendererWriteVRAM;
|
renderer->d.unlock = _unlock;
|
||||||
renderer->d.writeOAM = GBAVideoThreadProxyRendererWriteOAM;
|
renderer->d.wait = _wait;
|
||||||
renderer->d.writePalette = GBAVideoThreadProxyRendererWritePalette;
|
renderer->d.wake = _wake;
|
||||||
renderer->d.drawScanline = GBAVideoThreadProxyRendererDrawScanline;
|
|
||||||
renderer->d.finishFrame = GBAVideoThreadProxyRendererFinishFrame;
|
|
||||||
renderer->d.getPixels = GBAVideoThreadProxyRendererGetPixels;
|
|
||||||
renderer->d.putPixels = GBAVideoThreadProxyRendererPutPixels;
|
|
||||||
|
|
||||||
renderer->d.disableBG[0] = false;
|
renderer->d.logger.writeData = _writeData;
|
||||||
renderer->d.disableBG[1] = false;
|
renderer->d.logger.readData = _readData;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAVideoThreadProxyRendererInit(struct GBAVideoRenderer* renderer) {
|
void GBAVideoThreadProxyRendererInit(struct GBAVideoProxyRenderer* renderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
||||||
ConditionInit(&proxyRenderer->fromThreadCond);
|
ConditionInit(&proxyRenderer->fromThreadCond);
|
||||||
ConditionInit(&proxyRenderer->toThreadCond);
|
ConditionInit(&proxyRenderer->toThreadCond);
|
||||||
MutexInit(&proxyRenderer->mutex);
|
MutexInit(&proxyRenderer->mutex);
|
||||||
RingFIFOInit(&proxyRenderer->dirtyQueue, 0x40000);
|
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;
|
proxyRenderer->threadState = PROXY_THREAD_IDLE;
|
||||||
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAVideoThreadProxyRendererReset(struct GBAVideoRenderer* renderer) {
|
void GBAVideoThreadProxyRendererReset(struct GBAVideoProxyRenderer* renderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
||||||
MutexLock(&proxyRenderer->mutex);
|
MutexLock(&proxyRenderer->mutex);
|
||||||
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
||||||
ConditionWake(&proxyRenderer->toThreadCond);
|
ConditionWake(&proxyRenderer->toThreadCond);
|
||||||
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
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);
|
MutexUnlock(&proxyRenderer->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
|
void GBAVideoThreadProxyRendererDeinit(struct GBAVideoProxyRenderer* renderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
||||||
bool waiting = false;
|
bool waiting = false;
|
||||||
MutexLock(&proxyRenderer->mutex);
|
MutexLock(&proxyRenderer->mutex);
|
||||||
|
@ -120,9 +82,6 @@ void GBAVideoThreadProxyRendererDeinit(struct GBAVideoRenderer* renderer) {
|
||||||
ConditionDeinit(&proxyRenderer->fromThreadCond);
|
ConditionDeinit(&proxyRenderer->fromThreadCond);
|
||||||
ConditionDeinit(&proxyRenderer->toThreadCond);
|
ConditionDeinit(&proxyRenderer->toThreadCond);
|
||||||
MutexDeinit(&proxyRenderer->mutex);
|
MutexDeinit(&proxyRenderer->mutex);
|
||||||
proxyRenderer->backend->deinit(proxyRenderer->backend);
|
|
||||||
|
|
||||||
mVideoProxyRendererDeinit(&proxyRenderer->proxy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
|
void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
|
||||||
|
@ -138,8 +97,8 @@ void _proxyThreadRecover(struct GBAVideoThreadProxyRenderer* proxyRenderer) {
|
||||||
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
ThreadCreate(&proxyRenderer->thread, _proxyThread, proxyRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t length) {
|
static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = logger->context;
|
||||||
while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) {
|
while (!RingFIFOWrite(&proxyRenderer->dirtyQueue, data, length)) {
|
||||||
mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);
|
mLOG(GBA_VIDEO, DEBUG, "Can't write %"PRIz"u bytes. Proxy thread asleep?", length);
|
||||||
MutexLock(&proxyRenderer->mutex);
|
MutexLock(&proxyRenderer->mutex);
|
||||||
|
@ -155,8 +114,8 @@ static bool _writeData(struct mVideoProxy* proxy, const void* data, size_t lengt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool block) {
|
static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bool block) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
struct GBAVideoThreadProxyRenderer* proxyRenderer = logger->context;
|
||||||
bool read = false;
|
bool read = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
read = RingFIFORead(&proxyRenderer->dirtyQueue, data, length);
|
read = RingFIFORead(&proxyRenderer->dirtyQueue, data, length);
|
||||||
|
@ -172,139 +131,34 @@ static bool _readData(struct mVideoProxy* proxy, void* data, size_t length, bool
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _parsePacket(struct mVideoProxy* proxy, const struct mVideoProxyDirtyInfo* item) {
|
static void _lock(struct GBAVideoProxyRenderer* proxyRenderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
|
||||||
switch (item->type) {
|
MutexLock(&threadProxy->mutex);
|
||||||
case DIRTY_REGISTER:
|
|
||||||
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
|
|
||||||
break;
|
|
||||||
case DIRTY_PALETTE:
|
|
||||||
proxy->palette[item->address >> 1] = item->value;
|
|
||||||
proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value);
|
|
||||||
break;
|
|
||||||
case DIRTY_OAM:
|
|
||||||
proxy->oam[item->address] = item->value;
|
|
||||||
proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address);
|
|
||||||
break;
|
|
||||||
case DIRTY_VRAM:
|
|
||||||
proxy->readData(proxy, &proxy->vram[item->address >> 1], 0x1000, true);
|
|
||||||
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
|
|
||||||
break;
|
|
||||||
case DIRTY_SCANLINE:
|
|
||||||
proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address);
|
|
||||||
break;
|
|
||||||
case DIRTY_FLUSH:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t* _vramBlock(struct mVideoProxy* proxy, uint32_t address) {
|
static void _wait(struct GBAVideoProxyRenderer* proxyRenderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = proxy->context;
|
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
|
||||||
return &proxyRenderer->d.vram[address >> 1];
|
if (threadProxy->threadState == PROXY_THREAD_STOPPED) {
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
mLOG(GBA_VIDEO, ERROR, "Proxy thread stopped prematurely!");
|
mLOG(GBA_VIDEO, ERROR, "Proxy thread stopped prematurely!");
|
||||||
_proxyThreadRecover(proxyRenderer);
|
_proxyThreadRecover(threadProxy);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MutexLock(&proxyRenderer->mutex);
|
while (threadProxy->threadState == PROXY_THREAD_BUSY) {
|
||||||
// Insert an extra item into the queue to make sure it gets flushed
|
ConditionWake(&threadProxy->toThreadCond);
|
||||||
mVideoProxyRendererFlush(&proxyRenderer->proxy);
|
ConditionWait(&threadProxy->fromThreadCond, &threadProxy->mutex);
|
||||||
do {
|
}
|
||||||
ConditionWake(&proxyRenderer->toThreadCond);
|
|
||||||
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
||||||
} while (proxyRenderer->threadState == PROXY_THREAD_BUSY);
|
|
||||||
proxyRenderer->backend->finishFrame(proxyRenderer->backend);
|
|
||||||
MutexUnlock(&proxyRenderer->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBAVideoThreadProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
|
static void _unlock(struct GBAVideoProxyRenderer* proxyRenderer) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
|
||||||
MutexLock(&proxyRenderer->mutex);
|
MutexUnlock(&threadProxy->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 GBAVideoThreadProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
|
static void _wake(struct GBAVideoProxyRenderer* proxyRenderer, int y) {
|
||||||
struct GBAVideoThreadProxyRenderer* proxyRenderer = (struct GBAVideoThreadProxyRenderer*) renderer;
|
struct GBAVideoThreadProxyRenderer* threadProxy = (struct GBAVideoThreadProxyRenderer*) proxyRenderer;
|
||||||
MutexLock(&proxyRenderer->mutex);
|
if ((y & 15) == 15) {
|
||||||
// Insert an extra item into the queue to make sure it gets flushed
|
ConditionWake(&threadProxy->toThreadCond);
|
||||||
mVideoProxyRendererFlush(&proxyRenderer->proxy);
|
|
||||||
while (proxyRenderer->threadState == PROXY_THREAD_BUSY) {
|
|
||||||
ConditionWake(&proxyRenderer->toThreadCond);
|
|
||||||
ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex);
|
|
||||||
}
|
}
|
||||||
proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
|
|
||||||
MutexUnlock(&proxyRenderer->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static THREAD_ENTRY _proxyThread(void* renderer) {
|
static THREAD_ENTRY _proxyThread(void* renderer) {
|
||||||
|
@ -319,7 +173,7 @@ static THREAD_ENTRY _proxyThread(void* renderer) {
|
||||||
}
|
}
|
||||||
proxyRenderer->threadState = PROXY_THREAD_BUSY;
|
proxyRenderer->threadState = PROXY_THREAD_BUSY;
|
||||||
MutexUnlock(&proxyRenderer->mutex);
|
MutexUnlock(&proxyRenderer->mutex);
|
||||||
if (!mVideoProxyRendererRun(&proxyRenderer->proxy)) {
|
if (!mVideoLoggerRendererRun(&proxyRenderer->d.logger)) {
|
||||||
// FIFO was corrupted
|
// FIFO was corrupted
|
||||||
proxyRenderer->threadState = PROXY_THREAD_STOPPED;
|
proxyRenderer->threadState = PROXY_THREAD_STOPPED;
|
||||||
mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!");
|
mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!");
|
||||||
|
|
Loading…
Reference in New Issue