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