GB Video: Initial rendering work

This commit is contained in:
Jeffrey Pfau 2016-01-19 22:10:38 -08:00
parent 5fb2cfde1d
commit b7e80deda0
4 changed files with 94 additions and 22 deletions

View File

@ -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)];
}
}

View File

@ -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*);

View File

@ -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);
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH;
video->mode = 1;
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 {
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);
}
break;
case 1:
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);
++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;

View File

@ -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;