From b7e80deda0b85e0056a1a6b95ff06cf192e5385b Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 19 Jan 2016 22:10:38 -0800 Subject: [PATCH] GB Video: Initial rendering work --- src/gb/renderers/software.c | 55 +++++++++++++++++++++++++++++++++++-- src/gb/renderers/software.h | 5 ++++ src/gb/video.c | 45 ++++++++++++++++-------------- src/gb/video.h | 11 ++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index 64d9679fd..3b72f1835 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -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)]; + } +} diff --git a/src/gb/renderers/software.h b/src/gb/renderers/software.h index ca53709f6..2fbc5ad0e 100644 --- a/src/gb/renderers/software.h +++ b/src/gb/renderers/software.h @@ -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*); diff --git a/src/gb/video.c b/src/gb/video.c index ab980fc50..751c495d8 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -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; diff --git a/src/gb/video.h b/src/gb/video.h index f42efbf23..cf9771936 100644 --- a/src/gb/video.h +++ b/src/gb/video.h @@ -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;