GB: Video tester

This commit is contained in:
Vicki Pfau 2017-04-18 01:55:32 -07:00
parent 1b6531e320
commit d4deaf6292
9 changed files with 453 additions and 0 deletions

View File

@ -12,6 +12,7 @@ CXX_GUARD_START
struct mCore;
struct mCore* GBCoreCreate(void);
struct mCore* GBVideoLogPlayerCreate(void);
CXX_GUARD_END

View 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

View File

@ -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);

View File

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

View File

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

View File

@ -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
View 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);
}
}

View File

@ -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];

View File

@ -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) {