mirror of
https://github.com/libretro/mgba.git
synced 2024-12-02 21:37:10 +00:00
GB: Video tester
This commit is contained in:
parent
1b6531e320
commit
d4deaf6292
@ -12,6 +12,7 @@ CXX_GUARD_START
|
||||
|
||||
struct mCore;
|
||||
struct mCore* GBCoreCreate(void);
|
||||
struct mCore* GBVideoLogPlayerCreate(void);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
|
31
include/mgba/internal/gb/renderers/proxy.h
Normal file
31
include/mgba/internal/gb/renderers/proxy.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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 GB_VIDEO_PROXY_H
|
||||
#define GB_VIDEO_PROXY_H
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/internal/gb/video.h>
|
||||
#include "feature/video-logger.h"
|
||||
|
||||
struct GBVideoProxyRenderer {
|
||||
struct GBVideoRenderer d;
|
||||
struct GBVideoRenderer* backend;
|
||||
struct mVideoLogger* logger;
|
||||
|
||||
struct GBObj objThisLine[40];
|
||||
size_t oamMax;
|
||||
};
|
||||
|
||||
void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend);
|
||||
void GBVideoProxyRendererShim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer);
|
||||
void GBVideoProxyRendererUnshim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
@ -61,6 +61,7 @@ struct GBVideoRenderer {
|
||||
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
|
||||
void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value);
|
||||
void (*writeOAM)(struct GBVideoRenderer* renderer, uint16_t oam);
|
||||
void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* objOnLine, size_t nObj);
|
||||
void (*finishScanline)(struct GBVideoRenderer* renderer, int y);
|
||||
void (*finishFrame)(struct GBVideoRenderer* renderer);
|
||||
|
@ -12,6 +12,9 @@
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/gba/core.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/gb/core.h>
|
||||
#endif
|
||||
|
||||
const char mVL_MAGIC[] = "mVL\0";
|
||||
|
||||
@ -21,6 +24,9 @@ const static struct mVLDescriptor {
|
||||
} _descriptors[] = {
|
||||
#ifdef M_CORE_GBA
|
||||
{ PLATFORM_GBA, GBAVideoLogPlayerCreate },
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
{ PLATFORM_GB, GBVideoLogPlayerCreate },
|
||||
#endif
|
||||
{ PLATFORM_NONE, 0 }
|
||||
};
|
||||
|
137
src/gb/core.c
137
src/gb/core.c
@ -12,6 +12,7 @@
|
||||
#include <mgba/internal/gb/mbc.h>
|
||||
#include <mgba/internal/gb/overrides.h>
|
||||
#include <mgba/internal/gb/renderers/software.h>
|
||||
#include <mgba/internal/gb/renderers/proxy.h>
|
||||
#include <mgba/internal/gb/serialize.h>
|
||||
#include <mgba/internal/lr35902/lr35902.h>
|
||||
#include <mgba/internal/lr35902/debugger/debugger.h>
|
||||
@ -36,6 +37,9 @@ const static struct mCoreChannelInfo _GBAudioChannels[] = {
|
||||
struct GBCore {
|
||||
struct mCore d;
|
||||
struct GBVideoSoftwareRenderer renderer;
|
||||
struct GBVideoProxyRenderer proxyRenderer;
|
||||
struct mVideoLogContext* logContext;
|
||||
struct mCoreCallbacks logCallbacks;
|
||||
uint8_t keys;
|
||||
struct mCPUComponent* components[CPU_COMPONENT_MAX];
|
||||
const struct Configuration* overrides;
|
||||
@ -635,6 +639,42 @@ static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable
|
||||
}
|
||||
}
|
||||
|
||||
static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
struct GB* gb = core->board;
|
||||
gbcore->logContext = context;
|
||||
|
||||
context->initialStateSize = core->stateSize(core);
|
||||
context->initialState = anonymousMemoryMap(context->initialStateSize);
|
||||
core->saveState(core, context->initialState);
|
||||
|
||||
struct VFile* vf = VFileMemChunk(NULL, 0);
|
||||
context->nChannels = 1;
|
||||
context->channels[0].initialState = NULL;
|
||||
context->channels[0].initialStateSize = 0;
|
||||
context->channels[0].channelData = vf;
|
||||
context->channels[0].type = 0;
|
||||
gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
|
||||
mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, false);
|
||||
|
||||
gbcore->proxyRenderer.logger->vf = vf;
|
||||
gbcore->proxyRenderer.logger->block = false;
|
||||
|
||||
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, &gbcore->renderer.d);
|
||||
GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
|
||||
}
|
||||
|
||||
static void _GBCoreEndVideoLog(struct mCore* core) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
struct GB* gb = core->board;
|
||||
GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
|
||||
free(gbcore->proxyRenderer.logger);
|
||||
gbcore->proxyRenderer.logger = NULL;
|
||||
|
||||
mappedMemoryFree(gbcore->logContext->initialState, gbcore->logContext->initialStateSize);
|
||||
gbcore->logContext->channels[0].channelData->close(gbcore->logContext->channels[0].channelData);
|
||||
}
|
||||
|
||||
struct mCore* GBCoreCreate(void) {
|
||||
struct GBCore* gbcore = malloc(sizeof(*gbcore));
|
||||
struct mCore* core = &gbcore->d;
|
||||
@ -707,5 +747,102 @@ struct mCore* GBCoreCreate(void) {
|
||||
core->listAudioChannels = _GBCoreListAudioChannels;
|
||||
core->enableVideoLayer = _GBCoreEnableVideoLayer;
|
||||
core->enableAudioChannel = _GBCoreEnableAudioChannel;
|
||||
core->startVideoLog = _GBCoreStartVideoLog;
|
||||
core->endVideoLog = _GBCoreEndVideoLog;
|
||||
return core;
|
||||
}
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
static void _GBVLPStartFrameCallback(void *context) {
|
||||
struct mCore* core = context;
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
struct GB* gb = core->board;
|
||||
|
||||
if (!mVideoLoggerRendererRun(gbcore->proxyRenderer.logger, true)) {
|
||||
GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
|
||||
gbcore->proxyRenderer.logger->vf->seek(gbcore->proxyRenderer.logger->vf, 0, SEEK_SET);
|
||||
core->loadState(core, gbcore->logContext->initialState);
|
||||
GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
|
||||
|
||||
// Make sure CPU loop never spins
|
||||
GBHalt(gb->cpu);
|
||||
gb->memory.ie = 0;
|
||||
gb->memory.ime = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _GBVLPInit(struct mCore* core) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
if (!_GBCoreInit(core)) {
|
||||
return false;
|
||||
}
|
||||
gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
|
||||
mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, true);
|
||||
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, NULL);
|
||||
memset(&gbcore->logCallbacks, 0, sizeof(gbcore->logCallbacks));
|
||||
gbcore->logCallbacks.videoFrameStarted = _GBVLPStartFrameCallback;
|
||||
gbcore->logCallbacks.context = core;
|
||||
core->addCoreCallbacks(core, &gbcore->logCallbacks);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _GBVLPDeinit(struct mCore* core) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
if (gbcore->logContext) {
|
||||
mVideoLoggerDestroy(core, gbcore->logContext);
|
||||
}
|
||||
_GBCoreDeinit(core);
|
||||
}
|
||||
|
||||
static void _GBVLPReset(struct mCore* core) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
struct GB* gb = (struct GB*) core->board;
|
||||
if (gb->video.renderer == &gbcore->proxyRenderer.d) {
|
||||
GBVideoProxyRendererUnshim(&gb->video, &gbcore->proxyRenderer);
|
||||
} else if (gbcore->renderer.outputBuffer) {
|
||||
struct GBVideoRenderer* renderer = &gbcore->renderer.d;
|
||||
GBVideoAssociateRenderer(&gb->video, renderer);
|
||||
}
|
||||
gbcore->proxyRenderer.logger->vf->seek(gbcore->proxyRenderer.logger->vf, 0, SEEK_SET);
|
||||
|
||||
LR35902Reset(core->cpu);
|
||||
core->loadState(core, gbcore->logContext->initialState);
|
||||
GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
|
||||
|
||||
// Make sure CPU loop never spins
|
||||
GBHalt(gb->cpu);
|
||||
gb->memory.ie = 0;
|
||||
gb->memory.ime = false;
|
||||
}
|
||||
|
||||
static bool _GBVLPLoadROM(struct mCore* core, struct VFile* vf) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
gbcore->logContext = mVideoLoggerCreate(NULL);
|
||||
if (!mVideoLogContextLoad(vf, gbcore->logContext)) {
|
||||
mVideoLoggerDestroy(core, gbcore->logContext);
|
||||
gbcore->logContext = NULL;
|
||||
return false;
|
||||
}
|
||||
gbcore->proxyRenderer.logger->vf = gbcore->logContext->channels[0].channelData;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _returnTrue(struct VFile* vf) {
|
||||
UNUSED(vf);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct mCore* GBVideoLogPlayerCreate(void) {
|
||||
struct mCore* core = GBCoreCreate();
|
||||
core->init = _GBVLPInit;
|
||||
core->deinit = _GBVLPDeinit;
|
||||
core->reset = _GBVLPReset;
|
||||
core->loadROM = _GBVLPLoadROM;
|
||||
core->isROM = _returnTrue;
|
||||
return core;
|
||||
}
|
||||
#else
|
||||
struct mCore* GBVideoLogPlayerCreate(void) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -258,6 +258,7 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||
} else if (address < GB_BASE_UNUSABLE) {
|
||||
if (gb->video.mode < 2) {
|
||||
gb->video.oam.raw[address & 0xFF] = value;
|
||||
gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
|
||||
}
|
||||
} else if (address < GB_BASE_IO) {
|
||||
mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value);
|
||||
@ -395,6 +396,7 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL
|
||||
uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
|
||||
// TODO: Can DMA write OAM during modes 2-3?
|
||||
gb->video.oam.raw[gb->memory.dmaDest] = b;
|
||||
gb->video.renderer->writeOAM(gb->video.renderer, gb->memory.dmaDest);
|
||||
++gb->memory.dmaSource;
|
||||
++gb->memory.dmaDest;
|
||||
--gb->memory.dmaRemaining;
|
||||
@ -559,6 +561,7 @@ void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* o
|
||||
} else if (address < GB_BASE_UNUSABLE) {
|
||||
oldValue = gb->video.oam.raw[address & 0xFF];
|
||||
gb->video.oam.raw[address & 0xFF] = value;
|
||||
gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
|
||||
} else if (address < GB_BASE_HRAM) {
|
||||
mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address);
|
||||
return;
|
||||
|
258
src/gb/renderers/proxy.c
Normal file
258
src/gb/renderers/proxy.c
Normal file
@ -0,0 +1,258 @@
|
||||
/* 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/gb/renderers/proxy.h>
|
||||
|
||||
#include <mgba/core/tile-cache.h>
|
||||
#include <mgba/internal/gb/gb.h>
|
||||
#include <mgba/internal/gb/io.h>
|
||||
|
||||
#define BUFFER_OAM 1
|
||||
|
||||
static void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);
|
||||
static void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer);
|
||||
static uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
static void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
||||
static void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
|
||||
static void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int address, uint16_t value);
|
||||
static void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax);
|
||||
static void GBVideoProxyRendererFinishScanline(struct GBVideoRenderer* renderer, int y);
|
||||
static void GBVideoProxyRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoProxyRendererGetPixels(struct GBVideoRenderer* renderer, size_t* stride, const void** pixels);
|
||||
static void GBVideoProxyRendererPutPixels(struct GBVideoRenderer* 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 GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend) {
|
||||
renderer->d.init = GBVideoProxyRendererInit;
|
||||
renderer->d.deinit = GBVideoProxyRendererDeinit;
|
||||
renderer->d.writeVideoRegister = GBVideoProxyRendererWriteVideoRegister;
|
||||
renderer->d.writeVRAM = GBVideoProxyRendererWriteVRAM;
|
||||
renderer->d.writeOAM = GBVideoProxyRendererWriteOAM;
|
||||
renderer->d.writePalette = GBVideoProxyRendererWritePalette;
|
||||
renderer->d.drawRange = GBVideoProxyRendererDrawRange;
|
||||
renderer->d.finishScanline = GBVideoProxyRendererFinishScanline;
|
||||
renderer->d.finishFrame = GBVideoProxyRendererFinishFrame;
|
||||
renderer->d.getPixels = GBVideoProxyRendererGetPixels;
|
||||
renderer->d.putPixels = GBVideoProxyRendererPutPixels;
|
||||
|
||||
renderer->logger->context = renderer;
|
||||
renderer->logger->parsePacket = _parsePacket;
|
||||
renderer->logger->vramBlock = _vramBlock;
|
||||
renderer->logger->paletteSize = 0;
|
||||
renderer->logger->vramSize = GB_SIZE_VRAM;
|
||||
renderer->logger->oamSize = GB_SIZE_OAM;
|
||||
|
||||
renderer->backend = backend;
|
||||
}
|
||||
|
||||
static void _init(struct GBVideoProxyRenderer* proxyRenderer) {
|
||||
mVideoLoggerRendererInit(proxyRenderer->logger);
|
||||
|
||||
if (proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->vram = (uint8_t*) proxyRenderer->logger->vram;
|
||||
proxyRenderer->backend->oam = (union GBOAM*) proxyRenderer->logger->oam;
|
||||
proxyRenderer->backend->cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void _reset(struct GBVideoProxyRenderer* proxyRenderer) {
|
||||
memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, GB_SIZE_OAM);
|
||||
memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, GB_SIZE_VRAM);
|
||||
|
||||
mVideoLoggerRendererReset(proxyRenderer->logger);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererShim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer) {
|
||||
if ((renderer->backend && video->renderer != renderer->backend) || video->renderer == &renderer->d) {
|
||||
return;
|
||||
}
|
||||
renderer->backend = video->renderer;
|
||||
video->renderer = &renderer->d;
|
||||
renderer->d.cache = renderer->backend->cache;
|
||||
renderer->d.vram = video->vram;
|
||||
renderer->d.oam = &video->oam;
|
||||
_init(renderer);
|
||||
_reset(renderer);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererUnshim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer) {
|
||||
if (video->renderer != &renderer->d) {
|
||||
return;
|
||||
}
|
||||
renderer->backend->cache = video->renderer->cache;
|
||||
video->renderer = renderer->backend;
|
||||
renderer->backend->vram = video->vram;
|
||||
renderer->backend->oam = &video->oam;
|
||||
|
||||
mVideoLoggerRendererDeinit(renderer->logger);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
|
||||
_init(proxyRenderer);
|
||||
|
||||
proxyRenderer->backend->init(proxyRenderer->backend, model);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
|
||||
proxyRenderer->backend->deinit(proxyRenderer->backend);
|
||||
|
||||
mVideoLoggerRendererDeinit(proxyRenderer->logger);
|
||||
}
|
||||
|
||||
static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = logger->context;
|
||||
switch (item->type) {
|
||||
case DIRTY_REGISTER:
|
||||
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
|
||||
break;
|
||||
case DIRTY_PALETTE:
|
||||
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->finishScanline(proxyRenderer->backend, item->address);
|
||||
break;
|
||||
case DIRTY_RANGE:
|
||||
proxyRenderer->backend->drawRange(proxyRenderer->backend, item->value, item->value2, item->address, proxyRenderer->objThisLine, proxyRenderer->oamMax);
|
||||
break;
|
||||
case DIRTY_FRAME:
|
||||
proxyRenderer->backend->finishFrame(proxyRenderer->backend);
|
||||
break;
|
||||
case DIRTY_BUFFER:
|
||||
switch (item->address) {
|
||||
case BUFFER_OAM:
|
||||
proxyRenderer->oamMax = item->value2 / sizeof(struct GBObj);
|
||||
if (proxyRenderer->oamMax > 40) {
|
||||
return false;
|
||||
}
|
||||
logger->readData(logger, &proxyRenderer->objThisLine, item->value2, true);
|
||||
}
|
||||
break;
|
||||
case DIRTY_FLUSH:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = logger->context;
|
||||
return (uint16_t*) &proxyRenderer->d.vram[address];
|
||||
}
|
||||
|
||||
uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
|
||||
mVideoLoggerRendererWriteVideoRegister(proxyRenderer->logger, address, value);
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, address, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->writeVRAM(proxyRenderer->backend, address);
|
||||
}
|
||||
if (renderer->cache) {
|
||||
mTileCacheWriteVRAM(renderer->cache, address);
|
||||
}
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int address, uint16_t value) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
mVideoLoggerRendererWritePalette(proxyRenderer->logger, address, value);
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->writePalette(proxyRenderer->backend, address, value);
|
||||
}
|
||||
if (renderer->cache) {
|
||||
mTileCacheWritePalette(renderer->cache, address);
|
||||
}
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->writeOAM(proxyRenderer->backend, oam);
|
||||
}
|
||||
mVideoLoggerRendererWriteOAM(proxyRenderer->logger, oam, ((uint8_t*) proxyRenderer->d.oam->raw)[oam]);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->drawRange(proxyRenderer->backend, startX, endX, y, obj, oamMax);
|
||||
}
|
||||
mVideoLoggerWriteBuffer(proxyRenderer->logger, BUFFER_OAM, 0, oamMax * sizeof(*obj), obj);
|
||||
mVideoLoggerRendererDrawRange(proxyRenderer->logger, startX, endX, y);
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (!proxyRenderer->logger->block) {
|
||||
proxyRenderer->backend->finishScanline(proxyRenderer->backend, y);
|
||||
}
|
||||
mVideoLoggerRendererDrawScanline(proxyRenderer->logger, y);
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wake) {
|
||||
proxyRenderer->logger->wake(proxyRenderer->logger, y);
|
||||
}
|
||||
}
|
||||
|
||||
void GBVideoProxyRendererFinishFrame(struct GBVideoRenderer* renderer) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->lock(proxyRenderer->logger);
|
||||
proxyRenderer->logger->wait(proxyRenderer->logger);
|
||||
}
|
||||
mVideoLoggerRendererFinishFrame(proxyRenderer->logger);
|
||||
mVideoLoggerRendererFlush(proxyRenderer->logger);
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->unlock(proxyRenderer->logger);
|
||||
}
|
||||
}
|
||||
|
||||
static void GBVideoProxyRendererGetPixels(struct GBVideoRenderer* renderer, size_t* stride, const void** pixels) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->lock(proxyRenderer->logger);
|
||||
// Insert an extra item into the queue to make sure it gets flushed
|
||||
mVideoLoggerRendererFlush(proxyRenderer->logger);
|
||||
proxyRenderer->logger->wait(proxyRenderer->logger);
|
||||
}
|
||||
proxyRenderer->backend->getPixels(proxyRenderer->backend, stride, pixels);
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->unlock(proxyRenderer->logger);
|
||||
}
|
||||
}
|
||||
|
||||
static void GBVideoProxyRendererPutPixels(struct GBVideoRenderer* renderer, size_t stride, const void* pixels) {
|
||||
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->lock(proxyRenderer->logger);
|
||||
// Insert an extra item into the queue to make sure it gets flushed
|
||||
mVideoLoggerRendererFlush(proxyRenderer->logger);
|
||||
proxyRenderer->logger->wait(proxyRenderer->logger);
|
||||
}
|
||||
proxyRenderer->backend->putPixels(proxyRenderer->backend, stride, pixels);
|
||||
if (proxyRenderer->logger->block && proxyRenderer->logger->wait) {
|
||||
proxyRenderer->logger->unlock(proxyRenderer->logger);
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
|
||||
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value);
|
||||
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
||||
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
|
||||
static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax);
|
||||
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y);
|
||||
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||
@ -43,6 +44,7 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
|
||||
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
|
||||
renderer->d.writePalette = GBVideoSoftwareRendererWritePalette;
|
||||
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
|
||||
renderer->d.writeOAM = GBVideoSoftwareRendererWriteOAM;
|
||||
renderer->d.drawRange = GBVideoSoftwareRendererDrawRange;
|
||||
renderer->d.finishScanline = GBVideoSoftwareRendererFinishScanline;
|
||||
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
|
||||
@ -126,6 +128,12 @@ static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, u
|
||||
}
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(oam);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
|
@ -20,6 +20,7 @@ static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
|
||||
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value);
|
||||
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
||||
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
|
||||
static void GBVideoDummyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax);
|
||||
static void GBVideoDummyRendererFinishScanline(struct GBVideoRenderer* renderer, int y);
|
||||
static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||
@ -39,6 +40,7 @@ static struct GBVideoRenderer dummyRenderer = {
|
||||
.deinit = GBVideoDummyRendererDeinit,
|
||||
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
|
||||
.writeVRAM = GBVideoDummyRendererWriteVRAM,
|
||||
.writeOAM = GBVideoDummyRendererWriteOAM,
|
||||
.writePalette = GBVideoDummyRendererWritePalette,
|
||||
.drawRange = GBVideoDummyRendererDrawRange,
|
||||
.finishScanline = GBVideoDummyRendererFinishScanline,
|
||||
@ -469,6 +471,12 @@ static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint
|
||||
}
|
||||
}
|
||||
|
||||
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(oam);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) {
|
||||
UNUSED(value);
|
||||
if (renderer->cache) {
|
||||
|
Loading…
Reference in New Issue
Block a user