mirror of https://github.com/mgba-emu/mgba.git
GB Video: Initial rendering work
This commit is contained in:
parent
5fb2cfde1d
commit
b7e80deda0
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "software.h"
|
||||
|
||||
#include "gb/io.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer);
|
||||
|
@ -17,6 +18,8 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
|
|||
static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
|
||||
static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
|
||||
|
||||
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, int y);
|
||||
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
static const color_t GB_PALETTE[4] = { 0xFFFF, 0x39C7, 0x18C3, 0x0000};
|
||||
|
@ -74,7 +77,29 @@ static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, u
|
|||
}
|
||||
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
// TODO
|
||||
switch (address) {
|
||||
case REG_LCDC:
|
||||
softwareRenderer->lcdc = value;
|
||||
break;
|
||||
case REG_BGP:
|
||||
softwareRenderer->bgPalette[0] = GB_PALETTE[value & 3];
|
||||
softwareRenderer->bgPalette[1] = GB_PALETTE[(value >> 2) & 3];
|
||||
softwareRenderer->bgPalette[2] = GB_PALETTE[(value >> 4) & 3];
|
||||
softwareRenderer->bgPalette[3] = GB_PALETTE[(value >> 6) & 3];
|
||||
break;
|
||||
case REG_OBP0:
|
||||
softwareRenderer->objPalette[0][0] = GB_PALETTE[value & 3];
|
||||
softwareRenderer->objPalette[0][1] = GB_PALETTE[(value >> 2) & 3];
|
||||
softwareRenderer->objPalette[0][2] = GB_PALETTE[(value >> 4) & 3];
|
||||
softwareRenderer->objPalette[0][3] = GB_PALETTE[(value >> 6) & 3];
|
||||
break;
|
||||
case REG_OBP1:
|
||||
softwareRenderer->objPalette[1][0] = GB_PALETTE[value & 3];
|
||||
softwareRenderer->objPalette[1][1] = GB_PALETTE[(value >> 2) & 3];
|
||||
softwareRenderer->objPalette[1][2] = GB_PALETTE[(value >> 4) & 3];
|
||||
softwareRenderer->objPalette[1][3] = GB_PALETTE[(value >> 6) & 3];
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -83,7 +108,8 @@ static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer
|
|||
|
||||
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||
|
||||
// TODO
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, y);
|
||||
|
||||
size_t x;
|
||||
#ifdef COLOR_16_BIT
|
||||
#if defined(__ARM_NEON) && !defined(__APPLE__)
|
||||
|
@ -106,3 +132,28 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
|
|||
softwareRenderer->temporaryBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, int y) {
|
||||
uint8_t* maps = &renderer->d.vram[GB_BASE_MAP];
|
||||
if (GBRegisterLCDCIsTileMap(renderer->lcdc)) {
|
||||
maps += GB_SIZE_MAP;
|
||||
}
|
||||
uint8_t* data = renderer->d.vram;
|
||||
if (!GBRegisterLCDCIsTileData(renderer->lcdc)) {
|
||||
data += 0x1000;
|
||||
}
|
||||
int x;
|
||||
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||
int bgTile;
|
||||
if (GBRegisterLCDCIsTileData(renderer->lcdc)) {
|
||||
bgTile = maps[(x >> 3) + (0x20 * (y >> 3))];
|
||||
} else {
|
||||
bgTile = ((int8_t*) maps)[(x >> 3) + (0x20 * (y >> 3))];
|
||||
}
|
||||
uint8_t tileDataLower = data[(bgTile * 8 + (y & 7)) * 2];
|
||||
uint8_t tileDataUpper = data[(bgTile * 8 + (y & 7)) * 2 + 1];
|
||||
tileDataUpper >>= 7 - (x & 7);
|
||||
tileDataLower >>= 7 - (x & 7);
|
||||
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,12 @@ struct GBVideoSoftwareRenderer {
|
|||
|
||||
uint32_t row[GB_VIDEO_HORIZONTAL_PIXELS];
|
||||
|
||||
color_t bgPalette[4];
|
||||
color_t objPalette[2][4];
|
||||
|
||||
uint32_t* temporaryBuffer;
|
||||
|
||||
GBRegisterLCDC lcdc;
|
||||
};
|
||||
|
||||
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
|
||||
|
|
|
@ -82,38 +82,42 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
if (video->nextMode <= 0) {
|
||||
switch (video->mode) {
|
||||
case 0:
|
||||
if (video->ly < GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||
video->renderer->drawScanline(video->renderer, video->ly);
|
||||
}
|
||||
++video->ly;
|
||||
video->p->memory.io[REG_LY] = video->ly;
|
||||
if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||
video->ly = 0;
|
||||
++video->frameCounter;
|
||||
video->renderer->finishFrame(video->renderer);
|
||||
if (video->ly < GB_VIDEO_VERTICAL_PIXELS) {
|
||||
video->renderer->drawScanline(video->renderer, video->ly);
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
if (GBRegisterSTATIsOAMIRQ(video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
GBUpdateIRQs(video->p);
|
||||
}
|
||||
} else {
|
||||
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH;
|
||||
video->mode = 1;
|
||||
++video->frameCounter;
|
||||
video->renderer->finishFrame(video->renderer);
|
||||
if (GBRegisterSTATIsVblankIRQ(video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
}
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK);
|
||||
GBUpdateIRQs(video->p);
|
||||
} else {
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
if (GBRegisterSTATIsOAMIRQ(video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
GBUpdateIRQs(video->p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
++video->ly;
|
||||
if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||
video->ly = 0;
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
if (GBRegisterSTATIsOAMIRQ(video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
GBUpdateIRQs(video->p);
|
||||
}
|
||||
} else {
|
||||
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH;
|
||||
}
|
||||
video->p->memory.io[REG_LY] = video->ly;
|
||||
break;
|
||||
case 2:
|
||||
video->nextMode = GB_VIDEO_MODE_3_LENGTH;
|
||||
|
@ -144,6 +148,7 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
|
|||
video->mode = 2;
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->nextEvent = video->nextMode;
|
||||
video->eventDiff = 0;
|
||||
video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
|
||||
video->p->memory.io[REG_STAT] = video->stat;
|
||||
video->eventDiff = 0;
|
||||
|
|
|
@ -24,6 +24,9 @@ enum {
|
|||
|
||||
GB_VIDEO_MODE_1_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VBLANK_PIXELS,
|
||||
GB_VIDEO_TOTAL_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VERTICAL_TOTAL_PIXELS,
|
||||
|
||||
GB_BASE_MAP = 0x1800,
|
||||
GB_SIZE_MAP = 0x0400
|
||||
};
|
||||
|
||||
struct GBVideoRenderer {
|
||||
|
@ -43,6 +46,13 @@ struct GBVideoRenderer {
|
|||
};
|
||||
|
||||
DECL_BITFIELD(GBRegisterLCDC, uint8_t);
|
||||
DECL_BIT(GBRegisterLCDC, BgEnable, 0);
|
||||
DECL_BIT(GBRegisterLCDC, ObjEnable, 1);
|
||||
DECL_BIT(GBRegisterLCDC, ObjSize, 2);
|
||||
DECL_BIT(GBRegisterLCDC, TileMap, 3);
|
||||
DECL_BIT(GBRegisterLCDC, TileData, 4);
|
||||
DECL_BIT(GBRegisterLCDC, Window, 5);
|
||||
DECL_BIT(GBRegisterLCDC, WindowTileMap, 6);
|
||||
DECL_BIT(GBRegisterLCDC, Enable, 7);
|
||||
|
||||
DECL_BITFIELD(GBRegisterSTAT, uint8_t);
|
||||
|
@ -68,6 +78,7 @@ struct GBVideo {
|
|||
int32_t nextMode;
|
||||
|
||||
uint8_t* vram;
|
||||
uint8_t* vramBank;
|
||||
|
||||
int32_t frameCounter;
|
||||
int frameskip;
|
||||
|
|
Loading…
Reference in New Issue