src/gba/renderers/video-software.c (view raw)
1#include "video-software.h"
2
3#include "gba.h"
4#include "gba-io.h"
5
6static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
7static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
8static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
9static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
10static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer);
11
12static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer);
13static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareBackground* bg, uint16_t value);
14
15void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
16 renderer->d.init = GBAVideoSoftwareRendererInit;
17 renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
18 renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
19 renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
20 renderer->d.finishFrame = GBAVideoSoftwareRendererFinishFrame;
21
22 {
23 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
24 renderer->mutex = mutex;
25 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
26 renderer->cond = cond;
27 }
28}
29
30static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {
31 struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
32 int i;
33
34 softwareRenderer->dispcnt.packed = 0x0080;
35
36 for (i = 0; i < 4; ++i) {
37 struct GBAVideoSoftwareBackground* bg = &softwareRenderer->bg[i];
38 bg->index = i;
39 bg->enabled = 0;
40 bg->priority = 0;
41 bg->charBase = 0;
42 bg->mosaic = 0;
43 bg->multipalette = 0;
44 bg->screenBase = 0;
45 bg->overflow = 0;
46 bg->size = 0;
47 bg->x = 0;
48 bg->y = 0;
49 bg->refx = 0;
50 bg->refy = 0;
51 bg->dx = 256;
52 bg->dmx = 0;
53 bg->dy = 0;
54 bg->dmy = 256;
55 bg->sx = 0;
56 bg->sy = 0;
57 }
58
59 pthread_mutex_init(&softwareRenderer->mutex, 0);
60 pthread_cond_init(&softwareRenderer->cond, 0);
61}
62
63static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer) {
64 struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
65}
66
67static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
68 struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
69 switch (address) {
70 case REG_DISPCNT:
71 value &= 0xFFFB;
72 softwareRenderer->dispcnt.packed = value;
73 GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
74 break;
75 case REG_BG0CNT:
76 value &= 0xFFCF;
77 GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[0], value);
78 break;
79 case REG_BG1CNT:
80 value &= 0xFFCF;
81 GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[1], value);
82 break;
83 case REG_BG2CNT:
84 value &= 0xFFCF;
85 GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[2], value);
86 break;
87 case REG_BG3CNT:
88 value &= 0xFFCF;
89 GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[3], value);
90 break;
91 default:
92 GBALog(GBA_LOG_STUB, "Stub video register write: %03x", address);
93 }
94 return value;
95}
96
97static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
98 struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
99 int x;
100 uint16_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
101 if (softwareRenderer->dispcnt.forcedBlank) {
102 for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
103 row[x] = 0x7FFF;
104 }
105 return;
106 }
107 for (x = 0; x < 16; ++x) {
108 row[(x * 15) + 0] = renderer->palette[x + (y / 5) * 16];
109 row[(x * 15) + 1] = renderer->palette[x + (y / 5) * 16];
110 row[(x * 15) + 2] = renderer->palette[x + (y / 5) * 16];
111 row[(x * 15) + 3] = renderer->palette[x + (y / 5) * 16];
112 row[(x * 15) + 4] = renderer->palette[x + (y / 5) * 16];
113 row[(x * 15) + 5] = renderer->palette[x + (y / 5) * 16];
114 row[(x * 15) + 6] = renderer->palette[x + (y / 5) * 16];
115 row[(x * 15) + 7] = renderer->palette[x + (y / 5) * 16];
116 row[(x * 15) + 8] = renderer->palette[x + (y / 5) * 16];
117 row[(x * 15) + 9] = renderer->palette[x + (y / 5) * 16];
118 row[(x * 15) + 10] = renderer->palette[x + (y / 5) * 16];
119 row[(x * 15) + 11] = renderer->palette[x + (y / 5) * 16];
120 row[(x * 15) + 12] = renderer->palette[x + (y / 5) * 16];
121 row[(x * 15) + 13] = renderer->palette[x + (y / 5) * 16];
122 row[(x * 15) + 14] = renderer->palette[x + (y / 5) * 16];
123 }
124}
125
126static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {
127 struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
128
129 pthread_mutex_lock(&softwareRenderer->mutex);
130 pthread_cond_wait(&softwareRenderer->cond, &softwareRenderer->mutex);
131 pthread_mutex_unlock(&softwareRenderer->mutex);
132}
133
134static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer) {
135 renderer->bg[0].enabled = renderer->dispcnt.bg0Enable;
136 renderer->bg[1].enabled = renderer->dispcnt.bg1Enable;
137 renderer->bg[2].enabled = renderer->dispcnt.bg2Enable;
138 renderer->bg[3].enabled = renderer->dispcnt.bg3Enable;
139}
140
141static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
142 union GBARegisterBGCNT reg = { .packed = value };
143 bg->priority = reg.priority;
144 bg->charBase = reg.charBase << 13;
145 bg->mosaic = reg.mosaic;
146 bg->multipalette = reg.multipalette;
147 bg->screenBase = reg.screenBase << 10;
148 bg->overflow = reg.overflow;
149 bg->size = reg.size;
150}