all repos — mgba @ 488decf83a8ff476830f8afa7b68bbd898a04a03

mGBA Game Boy Advance Emulator

src/ds/renderers/software.c (view raw)

  1/* Copyright (c) 2013-2017 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 <mgba/internal/ds/renderers/software.h>
  7
  8#include <mgba/internal/arm/macros.h>
  9#include <mgba/internal/ds/io.h>
 10
 11static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer);
 12static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer);
 13static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer);
 14static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
 15static void DSVideoSoftwareRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
 16static void DSVideoSoftwareRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam);
 17static void DSVideoSoftwareRendererDrawScanline(struct DSVideoRenderer* renderer, int y);
 18static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer);
 19static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels);
 20static void DSVideoSoftwareRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels);
 21
 22void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) {
 23	renderer->d.init = DSVideoSoftwareRendererInit;
 24	renderer->d.reset = DSVideoSoftwareRendererReset;
 25	renderer->d.deinit = DSVideoSoftwareRendererDeinit;
 26	renderer->d.writeVideoRegister = DSVideoSoftwareRendererWriteVideoRegister;
 27	renderer->d.writePalette = DSVideoSoftwareRendererWritePalette;
 28	renderer->d.writeOAM = DSVideoSoftwareRendererWriteOAM;
 29	renderer->d.drawScanline = DSVideoSoftwareRendererDrawScanline;
 30	renderer->d.finishFrame = DSVideoSoftwareRendererFinishFrame;
 31	renderer->d.getPixels = DSVideoSoftwareRendererGetPixels;
 32	renderer->d.putPixels = DSVideoSoftwareRendererPutPixels;
 33
 34	renderer->engA.d.cache = NULL;
 35	GBAVideoSoftwareRendererCreate(&renderer->engA);
 36	renderer->engB.d.cache = NULL;
 37	GBAVideoSoftwareRendererCreate(&renderer->engB);
 38}
 39
 40static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer) {
 41	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
 42	softwareRenderer->engA.d.palette = &renderer->palette[0];
 43	softwareRenderer->engA.d.oam = &renderer->oam->oam[0];
 44	// TODO: VRAM
 45	softwareRenderer->engB.d.palette = &renderer->palette[512];
 46	softwareRenderer->engB.d.oam = &renderer->oam->oam[1];
 47	// TODO: VRAM
 48
 49	DSVideoSoftwareRendererReset(renderer);
 50}
 51
 52static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer) {
 53	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
 54	softwareRenderer->engA.d.reset(&softwareRenderer->engA.d);
 55	softwareRenderer->engB.d.reset(&softwareRenderer->engB.d);
 56}
 57
 58static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer) {
 59	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
 60	softwareRenderer->engA.d.deinit(&softwareRenderer->engA.d);
 61	softwareRenderer->engB.d.deinit(&softwareRenderer->engB.d);
 62}
 63
 64static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
 65	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
 66	if (address <= DS9_REG_A_BLDY) {
 67		value = softwareRenderer->engA.d.writeVideoRegister(&softwareRenderer->engA.d, address, value);
 68	} else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) {
 69		value = softwareRenderer->engB.d.writeVideoRegister(&softwareRenderer->engB.d, address & 0xFF, value);
 70	} else {
 71		mLOG(DS_VIDEO, STUB, "Stub video register write: %04X:%04X", address, value);
 72	}
 73	switch (address) {
 74	case DS9_REG_A_DISPCNT_LO:
 75		softwareRenderer->dispcntA &= 0xFFFF0000;
 76		softwareRenderer->dispcntA |= value;
 77		break;
 78	case DS9_REG_A_DISPCNT_HI:
 79		softwareRenderer->dispcntA &= 0x0000FFFF;
 80		softwareRenderer->dispcntA |= value << 16;
 81		break;
 82	case DS9_REG_B_DISPCNT_LO:
 83		softwareRenderer->dispcntB &= 0xFFFF0000;
 84		softwareRenderer->dispcntB |= value;
 85		break;
 86	case DS9_REG_B_DISPCNT_HI:
 87		softwareRenderer->dispcntB &= 0x0000FFFF;
 88		softwareRenderer->dispcntB |= value << 16;
 89		break;
 90	}
 91	return value;
 92}
 93
 94static void DSVideoSoftwareRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
 95	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
 96	if (address < 0x200) {
 97		softwareRenderer->engA.d.writePalette(&softwareRenderer->engA.d, address & 0x1FF, value);
 98	} else {
 99		softwareRenderer->engB.d.writePalette(&softwareRenderer->engB.d, address & 0x1FF, value);		
100	}
101}
102
103static void DSVideoSoftwareRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam) {
104	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
105	if (oam < 0x100) {
106		softwareRenderer->engA.d.writeOAM(&softwareRenderer->engA.d, oam & 0xFF);
107	} else {
108		softwareRenderer->engB.d.writeOAM(&softwareRenderer->engB.d, oam & 0xFF);
109	}
110}
111
112static void _drawScanlineA(struct DSVideoSoftwareRenderer* softwareRenderer, int y) {
113	memcpy(softwareRenderer->engA.d.vramBG, softwareRenderer->d.vramABG, sizeof(softwareRenderer->engA.d.vramBG));
114	memcpy(softwareRenderer->engA.d.vramOBJ, softwareRenderer->d.vramAOBJ, sizeof(softwareRenderer->engA.d.vramOBJ));
115	color_t* row = &softwareRenderer->engA.outputBuffer[softwareRenderer->outputBufferStride * y];
116
117	int x;
118	switch (DSRegisterDISPCNTGetDispMode(softwareRenderer->dispcntA)) {
119	case 0:
120		for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
121			row[x] = GBA_COLOR_WHITE;
122		}
123		return;
124	case 1:
125		softwareRenderer->engA.d.drawScanline(&softwareRenderer->engA.d, y);
126		return;
127	case 2: {
128		uint16_t* vram = &softwareRenderer->d.vram[0x10000 * DSRegisterDISPCNTGetVRAMBlock(softwareRenderer->dispcntA)];
129		for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
130			color_t color;
131			LOAD_16(color, (x + y * DS_VIDEO_HORIZONTAL_PIXELS) * 2, vram);
132#ifndef COLOR_16_BIT
133			unsigned color32 = 0;
134			color32 |= (color << 9) & 0xF80000;
135			color32 |= (color << 3) & 0xF8;
136			color32 |= (color << 6) & 0xF800;
137			color32 |= (color32 >> 5) & 0x070707;
138			color = color32;
139#elif COLOR_5_6_5
140			uint16_t color16 = 0;
141			color16 |= (color & 0x001F) << 11;
142			color16 |= (color & 0x03E0) << 1;
143			color16 |= (color & 0x7C00) >> 10;
144			color = color16;
145#endif
146			softwareRenderer->row[x] = color;
147		}
148		break;
149	}
150	case 3:
151		break;
152	}
153
154#ifdef COLOR_16_BIT
155#if defined(__ARM_NEON) && !defined(__APPLE__)
156	_to16Bit(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS);
157#else
158	for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
159		row[x] = softwareRenderer->row[x];
160	}
161#endif
162#else
163	memcpy(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS * sizeof(*row));
164#endif
165}
166
167static void _drawScanlineB(struct DSVideoSoftwareRenderer* softwareRenderer, int y) {
168	memcpy(softwareRenderer->engB.d.vramBG, softwareRenderer->d.vramBBG, sizeof(softwareRenderer->engB.d.vramBG));
169	memcpy(softwareRenderer->engB.d.vramOBJ, softwareRenderer->d.vramBOBJ, sizeof(softwareRenderer->engB.d.vramOBJ));
170	color_t* row = &softwareRenderer->engB.outputBuffer[softwareRenderer->outputBufferStride * y];
171
172	int x;
173	switch (DSRegisterDISPCNTGetDispMode(softwareRenderer->dispcntB)) {
174	case 0:
175		for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
176			row[x] = GBA_COLOR_WHITE;
177		}
178		return;
179	case 1:
180		softwareRenderer->engB.d.drawScanline(&softwareRenderer->engB.d, y);
181		return;
182	}
183
184#ifdef COLOR_16_BIT
185#if defined(__ARM_NEON) && !defined(__APPLE__)
186	_to16Bit(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS);
187#else
188	for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
189		row[x] = softwareRenderer->row[x];
190	}
191#endif
192#else
193	memcpy(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS * sizeof(*row));
194#endif
195}
196
197static void DSVideoSoftwareRendererDrawScanline(struct DSVideoRenderer* renderer, int y) {
198	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
199	softwareRenderer->engA.outputBuffer = softwareRenderer->outputBuffer;
200	softwareRenderer->engB.outputBuffer = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * DS_VIDEO_VERTICAL_PIXELS];
201	softwareRenderer->engA.outputBufferStride = softwareRenderer->outputBufferStride;
202	softwareRenderer->engB.outputBufferStride = softwareRenderer->outputBufferStride;
203
204
205	_drawScanlineA(softwareRenderer, y);
206	_drawScanlineB(softwareRenderer, y);
207}
208
209static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer) {
210	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
211	softwareRenderer->engA.d.finishFrame(&softwareRenderer->engA.d);
212	softwareRenderer->engB.d.finishFrame(&softwareRenderer->engB.d);
213}
214
215static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels) {
216	struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
217#ifdef COLOR_16_BIT
218#error Not yet supported
219#else
220	*stride = softwareRenderer->outputBufferStride;
221	*pixels = softwareRenderer->outputBuffer;
222#endif
223}
224
225static void DSVideoSoftwareRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels) {
226}