mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Convert video to mTiming
This commit is contained in:
parent
c056acb98f
commit
5b50c43857
|
@ -254,16 +254,6 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
|
||||||
nextEvent = cpu->nextEvent;
|
nextEvent = cpu->nextEvent;
|
||||||
} while (gba->cpuBlocked);
|
} while (gba->cpuBlocked);
|
||||||
|
|
||||||
testEvent = GBAVideoProcessEvents(&gba->video, cycles);
|
|
||||||
if (testEvent < nextEvent) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (testEvent == 0) {
|
|
||||||
mLOG(GBA, ERROR, "Video requiring 0 cycles");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
nextEvent = testEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
testEvent = GBAAudioProcessEvents(&gba->audio, cycles);
|
testEvent = GBAAudioProcessEvents(&gba->audio, cycles);
|
||||||
if (testEvent < nextEvent) {
|
if (testEvent < nextEvent) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
160
src/gba/video.c
160
src/gba/video.c
|
@ -29,6 +29,9 @@ static void GBAVideoDummyRendererFinishFrame(struct GBAVideoRenderer* renderer);
|
||||||
static void GBAVideoDummyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
|
static void GBAVideoDummyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
|
||||||
static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
|
static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
|
||||||
|
|
||||||
|
static void _startHblank(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||||
|
static void _startHdraw(struct mTiming*, void* context, uint32_t cyclesLate);
|
||||||
|
|
||||||
const int GBAVideoObjSizes[16][2] = {
|
const int GBAVideoObjSizes[16][2] = {
|
||||||
{ 8, 8 },
|
{ 8, 8 },
|
||||||
{ 16, 16 },
|
{ 16, 16 },
|
||||||
|
@ -67,6 +70,9 @@ void GBAVideoInit(struct GBAVideo* video) {
|
||||||
video->renderer->cache = NULL;
|
video->renderer->cache = NULL;
|
||||||
video->vram = 0;
|
video->vram = 0;
|
||||||
video->frameskip = 0;
|
video->frameskip = 0;
|
||||||
|
video->event.name = "GBA Video";
|
||||||
|
video->event.callback = NULL;
|
||||||
|
video->event.context = video;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAVideoReset(struct GBAVideo* video) {
|
void GBAVideoReset(struct GBAVideo* video) {
|
||||||
|
@ -78,9 +84,8 @@ void GBAVideoReset(struct GBAVideo* video) {
|
||||||
}
|
}
|
||||||
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
||||||
|
|
||||||
video->nextHblank = VIDEO_HDRAW_LENGTH;
|
video->event.callback = _startHblank;
|
||||||
video->nextEvent = video->nextHblank;
|
mTimingSchedule(&video->p->timing, &video->event, VIDEO_HDRAW_LENGTH);
|
||||||
video->eventDiff = 0;
|
|
||||||
|
|
||||||
video->frameCounter = 0;
|
video->frameCounter = 0;
|
||||||
video->frameskipCounter = 0;
|
video->frameskipCounter = 0;
|
||||||
|
@ -113,82 +118,77 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer*
|
||||||
video->renderer->init(video->renderer);
|
video->renderer->init(video->renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
|
void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||||
video->nextEvent -= cycles;
|
struct GBAVideo* video = context;
|
||||||
video->eventDiff += cycles;
|
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||||
if (video->nextEvent <= 0) {
|
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
|
||||||
int32_t lastEvent = video->nextEvent;
|
video->event.callback = _startHblank;
|
||||||
video->nextHblank -= video->eventDiff;
|
mTimingSchedule(timing, &video->event, VIDEO_HDRAW_LENGTH - cyclesLate);
|
||||||
video->eventDiff = 0;
|
|
||||||
uint16_t dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
|
||||||
|
|
||||||
if (GBARegisterDISPSTATIsInHblank(dispstat)) {
|
++video->vcount;
|
||||||
// End Hblank
|
if (video->vcount == VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||||
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
|
video->vcount = 0;
|
||||||
video->nextEvent = video->nextHblank;
|
|
||||||
|
|
||||||
++video->vcount;
|
|
||||||
if (video->vcount == VIDEO_VERTICAL_TOTAL_PIXELS) {
|
|
||||||
video->vcount = 0;
|
|
||||||
}
|
|
||||||
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
|
||||||
|
|
||||||
if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
|
|
||||||
dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
|
|
||||||
if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
|
|
||||||
GBARaiseIRQ(video->p, IRQ_VCOUNTER);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
|
|
||||||
}
|
|
||||||
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
|
||||||
|
|
||||||
// Note: state may be recorded during callbacks, so ensure it is consistent!
|
|
||||||
switch (video->vcount) {
|
|
||||||
case 0:
|
|
||||||
GBAFrameStarted(video->p);
|
|
||||||
break;
|
|
||||||
case VIDEO_VERTICAL_PIXELS:
|
|
||||||
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
|
|
||||||
if (video->frameskipCounter <= 0) {
|
|
||||||
video->renderer->finishFrame(video->renderer);
|
|
||||||
}
|
|
||||||
GBAMemoryRunVblankDMAs(video->p, lastEvent);
|
|
||||||
if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
|
|
||||||
GBARaiseIRQ(video->p, IRQ_VBLANK);
|
|
||||||
}
|
|
||||||
GBAFrameEnded(video->p);
|
|
||||||
--video->frameskipCounter;
|
|
||||||
if (video->frameskipCounter < 0) {
|
|
||||||
mCoreSyncPostFrame(video->p->sync);
|
|
||||||
video->frameskipCounter = video->frameskip;
|
|
||||||
}
|
|
||||||
++video->frameCounter;
|
|
||||||
break;
|
|
||||||
case VIDEO_VERTICAL_TOTAL_PIXELS - 1:
|
|
||||||
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Begin Hblank
|
|
||||||
dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
|
|
||||||
video->nextEvent = video->nextHblank + VIDEO_HBLANK_LENGTH;
|
|
||||||
video->nextHblank = video->nextEvent + VIDEO_HDRAW_LENGTH;
|
|
||||||
|
|
||||||
if (video->vcount < VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) {
|
|
||||||
video->renderer->drawScanline(video->renderer, video->vcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (video->vcount < VIDEO_VERTICAL_PIXELS) {
|
|
||||||
GBAMemoryRunHblankDMAs(video->p, lastEvent);
|
|
||||||
}
|
|
||||||
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
|
|
||||||
GBARaiseIRQ(video->p, IRQ_HBLANK);
|
|
||||||
}
|
|
||||||
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return video->nextEvent;
|
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
||||||
|
|
||||||
|
if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
|
||||||
|
dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
|
||||||
|
if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
|
||||||
|
GBARaiseIRQ(video->p, IRQ_VCOUNTER);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispstat = GBARegisterDISPSTATClearVcounter(dispstat);
|
||||||
|
}
|
||||||
|
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
||||||
|
|
||||||
|
// Note: state may be recorded during callbacks, so ensure it is consistent!
|
||||||
|
switch (video->vcount) {
|
||||||
|
case 0:
|
||||||
|
GBAFrameStarted(video->p);
|
||||||
|
break;
|
||||||
|
case VIDEO_VERTICAL_PIXELS:
|
||||||
|
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
|
||||||
|
if (video->frameskipCounter <= 0) {
|
||||||
|
video->renderer->finishFrame(video->renderer);
|
||||||
|
}
|
||||||
|
GBAMemoryRunVblankDMAs(video->p, -cyclesLate);
|
||||||
|
if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
|
||||||
|
GBARaiseIRQ(video->p, IRQ_VBLANK);
|
||||||
|
}
|
||||||
|
GBAFrameEnded(video->p);
|
||||||
|
--video->frameskipCounter;
|
||||||
|
if (video->frameskipCounter < 0) {
|
||||||
|
mCoreSyncPostFrame(video->p->sync);
|
||||||
|
video->frameskipCounter = video->frameskip;
|
||||||
|
}
|
||||||
|
++video->frameCounter;
|
||||||
|
break;
|
||||||
|
case VIDEO_VERTICAL_TOTAL_PIXELS - 1:
|
||||||
|
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||||
|
struct GBAVideo* video = context;
|
||||||
|
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||||
|
dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
|
||||||
|
video->event.callback = _startHdraw;
|
||||||
|
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - cyclesLate);
|
||||||
|
|
||||||
|
// Begin Hblank
|
||||||
|
dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
|
||||||
|
if (video->vcount < VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) {
|
||||||
|
video->renderer->drawScanline(video->renderer, video->vcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video->vcount < VIDEO_VERTICAL_PIXELS) {
|
||||||
|
GBAMemoryRunHblankDMAs(video->p, -cyclesLate);
|
||||||
|
}
|
||||||
|
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
|
||||||
|
GBARaiseIRQ(video->p, IRQ_HBLANK);
|
||||||
|
}
|
||||||
|
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value) {
|
void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value) {
|
||||||
|
@ -297,9 +297,6 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState*
|
||||||
memcpy(state->vram, video->renderer->vram, SIZE_VRAM);
|
memcpy(state->vram, video->renderer->vram, SIZE_VRAM);
|
||||||
memcpy(state->oam, video->oam.raw, SIZE_OAM);
|
memcpy(state->oam, video->oam.raw, SIZE_OAM);
|
||||||
memcpy(state->pram, video->palette, SIZE_PALETTE_RAM);
|
memcpy(state->pram, video->palette, SIZE_PALETTE_RAM);
|
||||||
STORE_32(video->nextEvent, 0, &state->video.nextEvent);
|
|
||||||
STORE_32(video->eventDiff, 0, &state->video.eventDiff);
|
|
||||||
STORE_32(video->nextHblank, 0, &state->video.nextHblank);
|
|
||||||
STORE_32(video->frameCounter, 0, &state->video.frameCounter);
|
STORE_32(video->frameCounter, 0, &state->video.frameCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +312,6 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState
|
||||||
LOAD_16(value, i, state->pram);
|
LOAD_16(value, i, state->pram);
|
||||||
GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0);
|
GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0);
|
||||||
}
|
}
|
||||||
LOAD_32(video->nextEvent, 0, &state->video.nextEvent);
|
|
||||||
LOAD_32(video->eventDiff, 0, &state->video.eventDiff);
|
|
||||||
LOAD_32(video->nextHblank, 0, &state->video.nextHblank);
|
|
||||||
LOAD_32(video->frameCounter, 0, &state->video.frameCounter);
|
LOAD_32(video->frameCounter, 0, &state->video.frameCounter);
|
||||||
LOAD_16(video->vcount, REG_VCOUNT, state->io);
|
LOAD_16(video->vcount, REG_VCOUNT, state->io);
|
||||||
video->renderer->reset(video->renderer);
|
video->renderer->reset(video->renderer);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "util/common.h"
|
#include "util/common.h"
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/timing.h"
|
||||||
#include "gba/memory.h"
|
#include "gba/memory.h"
|
||||||
|
|
||||||
mLOG_DECLARE_CATEGORY(GBA_VIDEO);
|
mLOG_DECLARE_CATEGORY(GBA_VIDEO);
|
||||||
|
@ -171,14 +172,11 @@ struct GBAVideoRenderer {
|
||||||
struct GBAVideo {
|
struct GBAVideo {
|
||||||
struct GBA* p;
|
struct GBA* p;
|
||||||
struct GBAVideoRenderer* renderer;
|
struct GBAVideoRenderer* renderer;
|
||||||
|
struct mTimingEvent event;
|
||||||
|
|
||||||
// VCOUNT
|
// VCOUNT
|
||||||
int vcount;
|
int vcount;
|
||||||
|
|
||||||
int32_t nextHblank;
|
|
||||||
int32_t nextEvent;
|
|
||||||
int32_t eventDiff;
|
|
||||||
|
|
||||||
uint16_t palette[SIZE_PALETTE_RAM >> 1];
|
uint16_t palette[SIZE_PALETTE_RAM >> 1];
|
||||||
uint16_t* vram;
|
uint16_t* vram;
|
||||||
union GBAOAM oam;
|
union GBAOAM oam;
|
||||||
|
@ -192,7 +190,6 @@ void GBAVideoInit(struct GBAVideo* video);
|
||||||
void GBAVideoReset(struct GBAVideo* video);
|
void GBAVideoReset(struct GBAVideo* video);
|
||||||
void GBAVideoDeinit(struct GBAVideo* video);
|
void GBAVideoDeinit(struct GBAVideo* video);
|
||||||
void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer* renderer);
|
void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer* renderer);
|
||||||
int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles);
|
|
||||||
|
|
||||||
void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value);
|
void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue