all repos — mgba @ 3ec0afa8fc5785f45f0c7a24a24ac5a684ab769f

mGBA Game Boy Advance Emulator

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}