all repos — mgba @ 7de2c91efb1e99409f9ab5bec0ae64580c2581e6

mGBA Game Boy Advance Emulator

src/gba/gba-video.c (view raw)

  1#include "gba-video.h"
  2
  3#include <limits.h>
  4
  5static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer);
  6static void GBAVideoDummyRendererDeinit(struct GBAVideoRenderer* renderer);
  7static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
  8static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
  9static void GBAVideoDummyRendererFinishFrame(struct GBAVideoRenderer* renderer);
 10
 11static struct GBAVideoRenderer dummyRenderer = {
 12	.init = GBAVideoDummyRendererInit,
 13	.deinit = GBAVideoDummyRendererDeinit,
 14	.writeVideoRegister = GBAVideoDummyRendererWriteVideoRegister,
 15	.drawScanline = GBAVideoDummyRendererDrawScanline,
 16	.finishFrame = GBAVideoDummyRendererFinishFrame
 17};
 18
 19void GBAVideoInit(struct GBAVideo* video) {
 20	video->renderer = &dummyRenderer;
 21
 22	video->inHblank = 0;
 23	video->inVblank = 0;
 24	video->vcounter = 0;
 25	video->vblankIRQ = 0;
 26	video->hblankIRQ = 0;
 27	video->vcounterIRQ = 0;
 28	video->vcountSetting = 0;
 29
 30	video->vcount = -1;
 31
 32	video->lastHblank = 0;
 33	video->nextHblank = VIDEO_HDRAW_LENGTH;
 34	video->nextEvent = video->nextHblank;
 35	video->eventDiff = video->nextEvent;
 36
 37	video->nextHblankIRQ = 0;
 38	video->nextVblankIRQ = 0;
 39	video->nextVcounterIRQ = 0;
 40}
 41
 42int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
 43	video->nextEvent -= cycles;
 44	if (video->nextEvent <= 0) {
 45		video->lastHblank -= video->eventDiff;
 46		video->nextHblank -= video->eventDiff;
 47		video->nextHblankIRQ -= video->eventDiff;
 48		video->nextVcounterIRQ -= video->eventDiff;
 49
 50		if (video->inHblank) {
 51			// End Hblank
 52			video->inHblank = 0;
 53			video->nextEvent = video->nextHblank;
 54
 55			++video->vcount;
 56
 57			switch (video->vcount) {
 58			case VIDEO_VERTICAL_PIXELS:
 59				video->inVblank = 1;
 60				video->renderer->finishFrame(video->renderer);
 61				video->nextVblankIRQ = video->nextEvent + VIDEO_TOTAL_LENGTH;
 62				//video->cpu.mmu.runVblankDmas();
 63				if (video->vblankIRQ) {
 64					//video->cpu.irq.raiseIRQ(video->cpu.irq.IRQ_VBLANK);
 65				}
 66				//video->vblankCallback();
 67				break;
 68			case VIDEO_VERTICAL_TOTAL_PIXELS - 1:
 69				video->inVblank = 0;
 70				break;
 71			case VIDEO_VERTICAL_TOTAL_PIXELS:
 72				video->vcount = 0;
 73				//video->renderPath.startDraw();
 74				break;
 75			}
 76
 77			video->vcounter = video->vcount == video->vcountSetting;
 78			if (video->vcounter && video->vcounterIRQ) {
 79				//video->cpu.irq.raiseIRQ(video->cpu.irq.IRQ_VCOUNTER);
 80				video->nextVcounterIRQ += VIDEO_TOTAL_LENGTH;
 81			}
 82
 83			if (video->vcount < VIDEO_VERTICAL_PIXELS) {
 84				video->renderer->drawScanline(video->renderer, video->vcount);
 85			}
 86		} else {
 87			// Begin Hblank
 88			video->inHblank = 1;
 89			video->lastHblank = video->nextHblank;
 90			video->nextEvent = video->lastHblank + VIDEO_HBLANK_LENGTH;
 91			video->nextHblank = video->nextEvent + VIDEO_HDRAW_LENGTH;
 92			video->nextHblankIRQ = video->nextHblank;
 93
 94			if (video->vcount < VIDEO_VERTICAL_PIXELS) {
 95				//video->cpu.mmu.runHblankDmas();
 96			}
 97			if (video->hblankIRQ) {
 98				//video->cpu.irq.raiseIRQ(video->cpu.irq.IRQ_HBLANK);
 99			}
100		}
101
102		video->eventDiff = video->nextEvent;
103	}
104	return video->nextEvent;
105}
106
107void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value) {
108	video->vblankIRQ = value & 0x0008;
109	video->hblankIRQ = value & 0x0010;
110	video->vcounterIRQ = value & 0x0020;
111	video->vcountSetting = (value & 0xFF00) >> 8;
112
113	if (video->vcounterIRQ) {
114		// FIXME: this can be too late if we're in the middle of an Hblank
115		video->nextVcounterIRQ = video->nextHblank + VIDEO_HBLANK_LENGTH + (video->vcountSetting - video->vcount) * VIDEO_HORIZONTAL_LENGTH;
116		if (video->nextVcounterIRQ < video->nextEvent) {
117			video->nextVcounterIRQ += VIDEO_TOTAL_LENGTH;
118		}
119	}
120}
121
122uint16_t GBAVideoReadDISPSTAT(struct GBAVideo* video) {
123	return (video->inVblank) | (video->inHblank << 1) | (video->vcounter << 2);
124}
125
126static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer) {
127	(void)(renderer);
128	// Nothing to do
129}
130
131static void GBAVideoDummyRendererDeinit(struct GBAVideoRenderer* renderer) {
132	(void)(renderer);
133	// Nothing to do
134}
135static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
136	(void)(renderer);
137	(void)(address);
138	return value;
139}
140
141static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
142	(void)(renderer);
143	(void)(y);
144	// Nothing to do
145}
146
147static void GBAVideoDummyRendererFinishFrame(struct GBAVideoRenderer* renderer) {
148	(void)(renderer);
149	printf("Drawing a frame\n");
150	// Nothing to do
151}