src/gb/video.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "video.h"
7
8#include "gb/gb.h"
9#include "gb/io.h"
10
11#include "util/memory.h"
12
13static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer);
14static void GBVideoDummyRendererReset(struct GBVideoRenderer* renderer);
15static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
16static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
17static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
18static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
19static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
20static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
21
22static struct GBVideoRenderer dummyRenderer = {
23 .init = GBVideoDummyRendererInit,
24 .reset = GBVideoDummyRendererReset,
25 .deinit = GBVideoDummyRendererDeinit,
26 .writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
27 .writeVRAM = GBVideoDummyRendererWriteVRAM,
28 .drawScanline = GBVideoDummyRendererDrawScanline,
29 .finishFrame = GBVideoDummyRendererFinishFrame,
30 .getPixels = GBVideoDummyRendererGetPixels
31};
32
33void GBVideoInit(struct GBVideo* video) {
34 video->renderer = &dummyRenderer;
35 video->vram = 0;
36 video->frameskip = 0;
37}
38
39void GBVideoReset(struct GBVideo* video) {
40 video->ly = 0;
41 video->mode = 1;
42
43 video->nextEvent = INT_MAX;
44 video->eventDiff = 0;
45
46 video->nextMode = INT_MAX;
47
48 video->frameCounter = 0;
49 video->frameskipCounter = 0;
50
51 if (video->vram) {
52 mappedMemoryFree(video->vram, GB_SIZE_VRAM);
53 }
54 video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
55 video->renderer->vram = video->vram;
56
57 video->renderer->deinit(video->renderer);
58 video->renderer->init(video->renderer);
59}
60
61void GBVideoDeinit(struct GBVideo* video) {
62 GBVideoAssociateRenderer(video, &dummyRenderer);
63 mappedMemoryFree(video->vram, GB_SIZE_VRAM);
64}
65
66void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) {
67 // TODO
68}
69
70int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
71 video->eventDiff += cycles;
72 if (video->nextEvent != INT_MAX) {
73 video->nextEvent -= cycles;
74 }
75 if (video->nextEvent <= 0) {
76 if (video->nextEvent != INT_MAX) {
77 video->nextMode -= video->eventDiff;
78 }
79 if (video->nextMode <= 0) {
80 video->mode = (video->mode + 1) & 3;
81 switch (video->mode) {
82 case 0:
83 video->nextMode = GB_VIDEO_MODE_0_LENGTH;
84 break;
85 case 1:
86 video->nextMode = GB_VIDEO_MODE_1_LENGTH;
87 break;
88 case 2:
89 video->nextMode = GB_VIDEO_MODE_2_LENGTH;
90 ++video->ly;
91 if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
92 video->ly = 0;
93 ++video->frameCounter;
94 }
95 video->p->memory.io[REG_LY] = video->ly;
96 break;
97 case 3:
98 video->nextMode = GB_VIDEO_MODE_3_LENGTH;
99 break;
100 }
101 }
102
103 video->nextEvent = video->nextMode;
104 video->eventDiff = 0;
105 }
106 return video->nextEvent;
107}
108
109void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
110 if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && GBRegisterLCDCIsEnable(value)) {
111 // TODO: Does enabling the LCD start in vblank?
112 video->mode = 2;
113 video->nextMode = GB_VIDEO_MODE_2_LENGTH;
114 video->nextEvent = video->nextMode;
115 video->eventDiff = 0;
116 if (video->nextEvent < video->p->cpu->nextEvent) {
117 video->p->cpu->nextEvent = video->nextEvent;
118 }
119 return;
120 }
121}
122
123static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer) {
124 UNUSED(renderer);
125 // Nothing to do
126}
127
128static void GBVideoDummyRendererReset(struct GBVideoRenderer* renderer) {
129 UNUSED(renderer);
130 // Nothing to do
131}
132
133static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer) {
134 UNUSED(renderer);
135 // Nothing to do
136}
137
138static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
139 UNUSED(renderer);
140 UNUSED(address);
141 return value;
142}
143
144static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
145 UNUSED(renderer);
146 UNUSED(address);
147 // Nothing to do
148}
149
150static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
151 UNUSED(renderer);
152 UNUSED(y);
153 // Nothing to do
154}
155
156static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer) {
157 UNUSED(renderer);
158 // Nothing to do
159}
160
161static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels) {
162 UNUSED(renderer);
163 UNUSED(stride);
164 UNUSED(pixels);
165 // Nothing to do
166}