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