GB Video: Further SGB work, support for ATTR_BLK

This commit is contained in:
Vicki Pfau 2017-08-02 14:47:23 -07:00
parent 36c1fb59be
commit 871c21fb6c
11 changed files with 307 additions and 121 deletions

View File

@ -4,7 +4,7 @@ Features:
- Game Boy Camera support - Game Boy Camera support
- Qt: Set default Game Boy colors - Qt: Set default Game Boy colors
- Game Boy Printer support - Game Boy Printer support
- Super Game Boy borders - Super Game Boy support
Bugfixes: Bugfixes:
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
- Python: Fix importing .gb or .gba before .core - Python: Fix importing .gb or .gba before .core

View File

@ -35,6 +35,28 @@ typedef uint32_t color_t;
#define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9)) #define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9))
#define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19)) #define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19))
#ifndef PYCPARSE
static inline color_t mColorFrom555(uint16_t value) {
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
color_t color = 0;
color |= (value & 0x001F) << 11;
color |= (value & 0x03E0) << 1;
color |= (value & 0x7C00) >> 10;
#else
color_t color = value;
#endif
#else
color_t color = 0;
color |= (value << 3) & 0xF8;
color |= (value << 6) & 0xF800;
color |= (value << 9) & 0xF80000;
color |= (color >> 5) & 0x070707;
#endif
return color;
}
#endif
struct blip_t; struct blip_t;
enum mColorFormat { enum mColorFormat {

View File

@ -23,6 +23,7 @@ struct GBVideoSoftwareRenderer {
uint8_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8]; uint8_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8];
color_t palette[128]; color_t palette[128];
uint8_t lookup[64];
uint32_t* temporaryBuffer; uint32_t* temporaryBuffer;
@ -37,6 +38,10 @@ struct GBVideoSoftwareRenderer {
int sgbTransfer; int sgbTransfer;
uint8_t sgbPacket[16]; uint8_t sgbPacket[16];
uint8_t sgbCommandHeader;
int sgbPacketId;
int sgbDataSets;
uint8_t sgbPartialDataSet[15];
}; };
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);

View File

@ -34,7 +34,8 @@ enum {
SGB_SIZE_CHAR_RAM = 0x2000, SGB_SIZE_CHAR_RAM = 0x2000,
SGB_SIZE_MAP_RAM = 0x1000, SGB_SIZE_MAP_RAM = 0x1000,
SGB_SIZE_PAL_RAM = 0x1000 SGB_SIZE_PAL_RAM = 0x1000,
SGB_SIZE_ATF_RAM = 0x1000
}; };
DECL_BITFIELD(GBObjAttributes, uint8_t); DECL_BITFIELD(GBObjAttributes, uint8_t);
@ -89,6 +90,8 @@ struct GBVideoRenderer {
uint8_t* sgbMapRam; uint8_t* sgbMapRam;
uint8_t* sgbPalRam; uint8_t* sgbPalRam;
int sgbRenderMode; int sgbRenderMode;
uint8_t* sgbAttributes;
uint8_t* sgbAttributeFiles;
bool disableBG; bool disableBG;
bool disableOBJ; bool disableOBJ;
@ -140,6 +143,7 @@ struct GBVideo {
bool bcpIncrement; bool bcpIncrement;
int ocpIndex; int ocpIndex;
bool ocpIncrement; bool ocpIncrement;
uint8_t sgbCommandHeader;
uint16_t dmgPalette[4]; uint16_t dmgPalette[4];
uint16_t palette[64]; uint16_t palette[64];

View File

@ -45,7 +45,7 @@ static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) {
} }
static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) { static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
int i; int i;
for (i = 0; i < 0x40; ++i) { for (i = 0; i < 0x40; ++i) {
uint16_t color; uint16_t color;
LOAD_16LE(color, 0x800 + i * 2, renderer->d.sgbMapRam); LOAD_16LE(color, 0x800 + i * 2, renderer->d.sgbMapRam);
@ -54,23 +54,24 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
int x, y; int x, y;
for (y = 0; y < 224; ++y) { for (y = 0; y < 224; ++y) {
for (x = 0; x < 256; x += 8) { for (x = 0; x < 256; x += 8) {
uint16_t mapData; if (x >= 48 && x < 208 && y >= 40 && y < 104) {
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
if (UNLIKELY(SGBBgAttributesGetTile(mapData) > 0x100)) {
continue; continue;
} }
uint16_t mapData;
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
continue;
}
int localY = y & 0x7; int localY = y & 0x7;
if (SGBBgAttributesIsYFlip(mapData)) { if (SGBBgAttributesIsYFlip(mapData)) {
localY = 7 - y; localY = 7 - localY;
} }
uint8_t tileData[4]; uint8_t tileData[4];
tileData[0] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x00]; tileData[0] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x00];
tileData[1] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x01]; tileData[1] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x01];
tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10]; tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10];
tileData[3] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x11]; tileData[3] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x11];
if (!(tileData[0] | tileData[1] | tileData[2] | tileData[3])) {
continue;
}
size_t base = y * renderer->outputBufferStride + x; size_t base = y * renderer->outputBufferStride + x;
int p = SGBBgAttributesGetPalette(mapData) * 0x10; int p = SGBBgAttributesGetPalette(mapData) * 0x10;
@ -97,6 +98,53 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
} }
} }
static inline void _setAttribute(uint8_t* sgbAttributes, unsigned x, unsigned y, int palette) {
int p = sgbAttributes[(x >> 2) + 5 * y];
p &= ~(3 << (2 * (3 - (x & 3))));
p |= palette << (2 * (3 - (x & 3)));
sgbAttributes[(x >> 2) + 5 * y] = p;
}
static void _parseAttrBlock(struct GBVideoSoftwareRenderer* renderer, int start) {
uint8_t block[6];
if (start < 0) {
memcpy(block, renderer->sgbPartialDataSet, -start);
memcpy(&block[-start], renderer->sgbPacket, 6 + start);
} else {
memcpy(block, &renderer->sgbPacket[start], 6);
}
unsigned x0 = block[2];
unsigned x1 = block[4];
unsigned y0 = block[3];
unsigned y1 = block[5];
unsigned x, y;
int pIn = block[1] & 3;
int pPerim = (block[1] >> 2) & 3;
int pOut = (block[1] >> 4) & 3;
for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS / 8; ++y) {
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++x) {
if (y > y0 && y < y1 && x > x0 && x < x1) {
if (block[0] & 1) {
_setAttribute(renderer->d.sgbAttributes, x, y, pIn);
}
} else if (y < y0 || y > y1 || x < x0 || x > x1) {
if (block[0] & 4) {
_setAttribute(renderer->d.sgbAttributes, x, y, pOut);
}
} else {
if (block[0] & 2) {
_setAttribute(renderer->d.sgbAttributes, x, y, pPerim);
} else if (block[0] & 1) {
_setAttribute(renderer->d.sgbAttributes, x, y, pIn);
} else if (block[0] & 4) {
_setAttribute(renderer->d.sgbAttributes, x, y, pOut);
}
}
}
}
}
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) { void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
renderer->d.init = GBVideoSoftwareRendererInit; renderer->d.init = GBVideoSoftwareRendererInit;
renderer->d.deinit = GBVideoSoftwareRendererDeinit; renderer->d.deinit = GBVideoSoftwareRendererDeinit;
@ -128,6 +176,14 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
softwareRenderer->wx = 0; softwareRenderer->wx = 0;
softwareRenderer->model = model; softwareRenderer->model = model;
softwareRenderer->sgbTransfer = 0; softwareRenderer->sgbTransfer = 0;
softwareRenderer->sgbCommandHeader = 0;
int i;
for (i = 0; i < 64; ++i) {
softwareRenderer->lookup[i] = i;
softwareRenderer->lookup[i] = i;
softwareRenderer->lookup[i] = i;
softwareRenderer->lookup[i] = i;
}
} }
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) { static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
@ -153,6 +209,24 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
case REG_WX: case REG_WX:
softwareRenderer->wx = value; softwareRenderer->wx = value;
break; break;
case REG_BGP:
softwareRenderer->lookup[0] = value & 3;
softwareRenderer->lookup[1] = (value >> 2) & 3;
softwareRenderer->lookup[2] = (value >> 4) & 3;
softwareRenderer->lookup[3] = (value >> 6) & 3;
break;
case REG_OBP0:
softwareRenderer->lookup[0x20 + 0] = value & 3;
softwareRenderer->lookup[0x20 + 1] = (value >> 2) & 3;
softwareRenderer->lookup[0x20 + 2] = (value >> 4) & 3;
softwareRenderer->lookup[0x20 + 3] = (value >> 6) & 3;
break;
case REG_OBP1:
softwareRenderer->lookup[0x24 + 0] = value & 3;
softwareRenderer->lookup[0x24 + 1] = (value >> 2) & 3;
softwareRenderer->lookup[0x24 + 2] = (value >> 4) & 3;
softwareRenderer->lookup[0x24 + 3] = (value >> 6) & 3;
break;
} }
return value; return value;
} }
@ -160,26 +234,48 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) { static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
memcpy(softwareRenderer->sgbPacket, data, sizeof(softwareRenderer->sgbPacket)); memcpy(softwareRenderer->sgbPacket, data, sizeof(softwareRenderer->sgbPacket));
int i;
if (!(softwareRenderer->sgbCommandHeader & 7)) {
softwareRenderer->sgbCommandHeader = data[0];
softwareRenderer->sgbPacketId = 0;
softwareRenderer->sgbTransfer = 0;
}
--softwareRenderer->sgbCommandHeader;
++softwareRenderer->sgbPacketId;
int set;
switch (softwareRenderer->sgbCommandHeader >> 3) {
case SGB_PAL_SET:
softwareRenderer->sgbPacket[1] = data[9];
if (!(data[9] & 0x80)) {
break;
}
// Fall through
case SGB_ATTR_SET:
set = softwareRenderer->sgbPacket[1] & 0x3F;
if (set <= 0x2C) {
memcpy(renderer->sgbAttributes, &renderer->sgbAttributeFiles[set * 90], 90);
}
break;
case SGB_ATTR_BLK:
if (softwareRenderer->sgbPacketId == 1) {
softwareRenderer->sgbDataSets = softwareRenderer->sgbPacket[1];
i = 2;
} else {
i = (9 - softwareRenderer->sgbPacketId) % 3 * -2;
}
for (; i <= 10 && softwareRenderer->sgbDataSets; i += 6, --softwareRenderer->sgbDataSets) {
_parseAttrBlock(softwareRenderer, i);
}
if (i < 16 && softwareRenderer->sgbDataSets) {
memcpy(softwareRenderer->sgbPartialDataSet, &softwareRenderer->sgbPacket[i], 16 - i);
}
break;
}
} }
static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
#ifdef COLOR_16_BIT color_t color = mColorFrom555(value);
#ifdef COLOR_5_6_5
color_t color = 0;
color |= (value & 0x001F) << 11;
color |= (value & 0x03E0) << 1;
color |= (value & 0x7C00) >> 10;
#else
color_t color = value;
#endif
#else
color_t color = 0;
color |= (value << 3) & 0xF8;
color |= (value << 6) & 0xF800;
color |= (value << 9) & 0xF80000;
color |= (color >> 5) & 0x070707;
#endif
softwareRenderer->palette[index] = color; softwareRenderer->palette[index] = color;
if (renderer->cache) { if (renderer->cache) {
mTileCacheWritePalette(renderer->cache, index << 1); mTileCacheWritePalette(renderer->cache, index << 1);
@ -233,6 +329,10 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
GBVideoSoftwareRendererDrawObj(softwareRenderer, &obj[i], startX, endX, y); GBVideoSoftwareRendererDrawObj(softwareRenderer, &obj[i], startX, endX, y);
} }
} }
}
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
size_t sgbOffset = 0; size_t sgbOffset = 0;
if (softwareRenderer->model == GB_MODEL_SGB) { if (softwareRenderer->model == GB_MODEL_SGB) {
sgbOffset = softwareRenderer->outputBufferStride * 40 + 48; sgbOffset = softwareRenderer->outputBufferStride * 40 + 48;
@ -241,24 +341,28 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
int x; int x;
switch (softwareRenderer->d.sgbRenderMode) { switch (softwareRenderer->d.sgbRenderMode) {
case 0: case 0:
for (x = startX; x + 7 < (endX & ~7); x += 8) { for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 8) {
row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F]; int p = 0;
row[x + 1] = softwareRenderer->palette[softwareRenderer->row[x + 1] & 0x7F]; if (softwareRenderer->model == GB_MODEL_SGB) {
row[x + 2] = softwareRenderer->palette[softwareRenderer->row[x + 2] & 0x7F]; p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)];
row[x + 3] = softwareRenderer->palette[softwareRenderer->row[x + 3] & 0x7F]; p >>= 6 - ((x / 4) & 0x6);
row[x + 4] = softwareRenderer->palette[softwareRenderer->row[x + 4] & 0x7F]; p &= 3;
row[x + 5] = softwareRenderer->palette[softwareRenderer->row[x + 5] & 0x7F]; p <<= 2;
row[x + 6] = softwareRenderer->palette[softwareRenderer->row[x + 6] & 0x7F]; }
row[x + 7] = softwareRenderer->palette[softwareRenderer->row[x + 7] & 0x7F]; row[x + 0] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & 0x7F]];
} row[x + 1] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 1] & 0x7F]];
for (; x < endX; ++x) { row[x + 2] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 2] & 0x7F]];
row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F]; row[x + 3] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 3] & 0x7F]];
row[x + 4] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 4] & 0x7F]];
row[x + 5] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 5] & 0x7F]];
row[x + 6] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 6] & 0x7F]];
row[x + 7] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 7] & 0x7F]];
} }
break; break;
case 1: case 1:
return; break;
case 2: case 2:
for (x = startX; x + 7 < (endX & ~7); x += 8) { for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 8) {
row[x] = 0; row[x] = 0;
row[x + 1] = 0; row[x + 1] = 0;
row[x + 2] = 0; row[x + 2] = 0;
@ -268,12 +372,9 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
row[x + 6] = 0; row[x + 6] = 0;
row[x + 7] = 0; row[x + 7] = 0;
} }
for (; x < endX; ++x) { break;
row[x] = 0;
}
return;
case 3: case 3:
for (x = startX; x + 7 < (endX & ~7); x += 8) { for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 8) {
row[x] = softwareRenderer->palette[0]; row[x] = softwareRenderer->palette[0];
row[x + 1] = softwareRenderer->palette[0]; row[x + 1] = softwareRenderer->palette[0];
row[x + 2] = softwareRenderer->palette[0]; row[x + 2] = softwareRenderer->palette[0];
@ -283,21 +384,19 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
row[x + 6] = softwareRenderer->palette[0]; row[x + 6] = softwareRenderer->palette[0];
row[x + 7] = softwareRenderer->palette[0]; row[x + 7] = softwareRenderer->palette[0];
} }
for (; x < endX; ++x) { break;
row[x] = softwareRenderer->palette[0];
}
return;
} }
}
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && softwareRenderer->wx - 7 < GB_VIDEO_HORIZONTAL_PIXELS) { if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && softwareRenderer->wx - 7 < GB_VIDEO_HORIZONTAL_PIXELS) {
++softwareRenderer->currentWy; ++softwareRenderer->currentWy;
} }
if (softwareRenderer->sgbTransfer == 1) { if (softwareRenderer->sgbTransfer == 1) {
size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS);
if (offset >= 0x1000) {
return;
}
uint8_t* buffer = NULL; uint8_t* buffer = NULL;
switch (softwareRenderer->sgbPacket[0] >> 3) { switch (softwareRenderer->sgbCommandHeader >> 3) {
case SGB_PAL_TRN: case SGB_PAL_TRN:
buffer = renderer->sgbPalRam; buffer = renderer->sgbPalRam;
break; break;
@ -307,38 +406,38 @@ static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* render
case SGB_PCT_TRN: case SGB_PCT_TRN:
buffer = renderer->sgbMapRam; buffer = renderer->sgbMapRam;
break; break;
case SGB_ATTR_TRN:
buffer = renderer->sgbAttributeFiles;
break;
default: default:
break; break;
} }
if (buffer) { if (buffer) {
size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS); int i;
if (offset < 0x1000) { for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS; i += 8) {
int i; if (UNLIKELY(offset + (i << 1) + 1 >= 0x1000)) {
for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS; i += 8) { break;
if (UNLIKELY(offset + (i << 1) + 1 >= 0x1000)) {
break;
}
uint8_t hi = 0;
uint8_t lo = 0;
hi |= (softwareRenderer->row[i + 0] & 0x2) << 6;
lo |= (softwareRenderer->row[i + 0] & 0x1) << 7;
hi |= (softwareRenderer->row[i + 1] & 0x2) << 5;
lo |= (softwareRenderer->row[i + 1] & 0x1) << 6;
hi |= (softwareRenderer->row[i + 2] & 0x2) << 4;
lo |= (softwareRenderer->row[i + 2] & 0x1) << 5;
hi |= (softwareRenderer->row[i + 3] & 0x2) << 3;
lo |= (softwareRenderer->row[i + 3] & 0x1) << 4;
hi |= (softwareRenderer->row[i + 4] & 0x2) << 2;
lo |= (softwareRenderer->row[i + 4] & 0x1) << 3;
hi |= (softwareRenderer->row[i + 5] & 0x2) << 1;
lo |= (softwareRenderer->row[i + 5] & 0x1) << 2;
hi |= (softwareRenderer->row[i + 6] & 0x2) << 0;
lo |= (softwareRenderer->row[i + 6] & 0x1) << 1;
hi |= (softwareRenderer->row[i + 7] & 0x2) >> 1;
lo |= (softwareRenderer->row[i + 7] & 0x1) >> 0;
buffer[offset + (i << 1) + 0] = lo;
buffer[offset + (i << 1) + 1] = hi;
} }
uint8_t hi = 0;
uint8_t lo = 0;
hi |= (softwareRenderer->row[i + 0] & 0x2) << 6;
lo |= (softwareRenderer->row[i + 0] & 0x1) << 7;
hi |= (softwareRenderer->row[i + 1] & 0x2) << 5;
lo |= (softwareRenderer->row[i + 1] & 0x1) << 6;
hi |= (softwareRenderer->row[i + 2] & 0x2) << 4;
lo |= (softwareRenderer->row[i + 2] & 0x1) << 5;
hi |= (softwareRenderer->row[i + 3] & 0x2) << 3;
lo |= (softwareRenderer->row[i + 3] & 0x1) << 4;
hi |= (softwareRenderer->row[i + 4] & 0x2) << 2;
lo |= (softwareRenderer->row[i + 4] & 0x1) << 3;
hi |= (softwareRenderer->row[i + 5] & 0x2) << 1;
lo |= (softwareRenderer->row[i + 5] & 0x1) << 2;
hi |= (softwareRenderer->row[i + 6] & 0x2) << 0;
lo |= (softwareRenderer->row[i + 6] & 0x1) << 1;
hi |= (softwareRenderer->row[i + 7] & 0x2) >> 1;
lo |= (softwareRenderer->row[i + 7] & 0x1) >> 0;
buffer[offset + (i << 1) + 0] = lo;
buffer[offset + (i << 1) + 1] = hi;
} }
} }
} }
@ -355,12 +454,8 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
_clearScreen(softwareRenderer); _clearScreen(softwareRenderer);
} }
if (softwareRenderer->model == GB_MODEL_SGB) { if (softwareRenderer->model == GB_MODEL_SGB) {
switch (softwareRenderer->sgbPacket[0] >> 3) { switch (softwareRenderer->sgbCommandHeader >> 3) {
case SGB_PAL_SET: case SGB_PAL_SET:
if (softwareRenderer->sgbPacket[9] & 0x40) {
renderer->sgbRenderMode = 0;
}
break;
case SGB_ATTR_SET: case SGB_ATTR_SET:
if (softwareRenderer->sgbPacket[1] & 0x40) { if (softwareRenderer->sgbPacket[1] & 0x40) {
renderer->sgbRenderMode = 0; renderer->sgbRenderMode = 0;
@ -373,10 +468,11 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
// Make sure every buffer sees this if we're multibuffering // Make sure every buffer sees this if we're multibuffering
_regenerateSGBBorder(softwareRenderer); _regenerateSGBBorder(softwareRenderer);
} }
// Fall through
case SGB_ATTR_TRN:
++softwareRenderer->sgbTransfer; ++softwareRenderer->sgbTransfer;
if (softwareRenderer->sgbTransfer == 5) { if (softwareRenderer->sgbTransfer == 5) {
softwareRenderer->sgbTransfer = 0; softwareRenderer->sgbCommandHeader = 0;
softwareRenderer->sgbPacket[0] = 0;
} }
default: default:
break; break;

View File

@ -75,6 +75,8 @@ void GBVideoInit(struct GBVideo* video) {
video->renderer->sgbCharRam = NULL; video->renderer->sgbCharRam = NULL;
video->renderer->sgbMapRam = NULL; video->renderer->sgbMapRam = NULL;
video->renderer->sgbPalRam = NULL; video->renderer->sgbPalRam = NULL;
video->renderer->sgbAttributes = NULL;
video->renderer->sgbAttributeFiles = NULL;
} }
void GBVideoReset(struct GBVideo* video) { void GBVideoReset(struct GBVideo* video) {
@ -100,10 +102,40 @@ void GBVideoReset(struct GBVideo* video) {
video->renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM); video->renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
video->renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM); video->renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
video->renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM); video->renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
video->renderer->sgbAttributeFiles = anonymousMemoryMap(SGB_SIZE_ATF_RAM);
video->renderer->sgbAttributes = malloc(90 * 45);
memset(video->renderer->sgbAttributes, 0, 90 * 45);
video->sgbCommandHeader = 0;
} }
video->palette[0] = video->dmgPalette[0];
video->palette[1] = video->dmgPalette[1];
video->palette[2] = video->dmgPalette[2];
video->palette[3] = video->dmgPalette[3];
video->palette[8 * 4 + 0] = video->dmgPalette[0];
video->palette[8 * 4 + 1] = video->dmgPalette[1];
video->palette[8 * 4 + 2] = video->dmgPalette[2];
video->palette[8 * 4 + 3] = video->dmgPalette[3];
video->palette[9 * 4 + 0] = video->dmgPalette[0];
video->palette[9 * 4 + 1] = video->dmgPalette[1];
video->palette[9 * 4 + 2] = video->dmgPalette[2];
video->palette[9 * 4 + 3] = video->dmgPalette[3];
video->renderer->deinit(video->renderer); video->renderer->deinit(video->renderer);
video->renderer->init(video->renderer, video->p->model); video->renderer->init(video->renderer, video->p->model);
video->renderer->writePalette(video->renderer, 0, video->palette[0]);
video->renderer->writePalette(video->renderer, 1, video->palette[1]);
video->renderer->writePalette(video->renderer, 2, video->palette[2]);
video->renderer->writePalette(video->renderer, 3, video->palette[3]);
video->renderer->writePalette(video->renderer, 8 * 4 + 0, video->palette[8 * 4 + 0]);
video->renderer->writePalette(video->renderer, 8 * 4 + 1, video->palette[8 * 4 + 1]);
video->renderer->writePalette(video->renderer, 8 * 4 + 2, video->palette[8 * 4 + 2]);
video->renderer->writePalette(video->renderer, 8 * 4 + 3, video->palette[8 * 4 + 3]);
video->renderer->writePalette(video->renderer, 9 * 4 + 0, video->palette[9 * 4 + 0]);
video->renderer->writePalette(video->renderer, 9 * 4 + 1, video->palette[9 * 4 + 1]);
video->renderer->writePalette(video->renderer, 9 * 4 + 2, video->palette[9 * 4 + 2]);
video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]);
} }
void GBVideoDeinit(struct GBVideo* video) { void GBVideoDeinit(struct GBVideo* video) {
@ -121,6 +153,14 @@ void GBVideoDeinit(struct GBVideo* video) {
mappedMemoryFree(video->renderer->sgbPalRam, SGB_SIZE_PAL_RAM); mappedMemoryFree(video->renderer->sgbPalRam, SGB_SIZE_PAL_RAM);
video->renderer->sgbPalRam = NULL; video->renderer->sgbPalRam = NULL;
} }
if (video->renderer->sgbAttributeFiles) {
mappedMemoryFree(video->renderer->sgbAttributeFiles, SGB_SIZE_ATF_RAM);
video->renderer->sgbAttributeFiles = NULL;
}
if (video->renderer->sgbAttributes) {
free(video->renderer->sgbAttributes);
video->renderer->sgbAttributes = NULL;
}
} }
void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) { void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) {
@ -130,6 +170,8 @@ void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* ren
renderer->sgbCharRam = video->renderer->sgbCharRam; renderer->sgbCharRam = video->renderer->sgbCharRam;
renderer->sgbMapRam = video->renderer->sgbMapRam; renderer->sgbMapRam = video->renderer->sgbMapRam;
renderer->sgbPalRam = video->renderer->sgbPalRam; renderer->sgbPalRam = video->renderer->sgbPalRam;
renderer->sgbAttributeFiles = video->renderer->sgbAttributeFiles;
renderer->sgbAttributes = video->renderer->sgbAttributes;
video->renderer = renderer; video->renderer = renderer;
renderer->vram = video->vram; renderer->vram = video->vram;
video->renderer->init(video->renderer, video->p->model); video->renderer->init(video->renderer, video->p->model);
@ -419,7 +461,7 @@ void GBVideoWriteLYC(struct GBVideo* video, uint8_t value) {
} }
void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) { void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) {
if (video->p->model < GB_MODEL_CGB) { if (video->p->model < GB_MODEL_SGB) {
switch (address) { switch (address) {
case REG_BGP: case REG_BGP:
video->palette[0] = video->dmgPalette[value & 3]; video->palette[0] = video->dmgPalette[value & 3];
@ -452,6 +494,8 @@ void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value)
video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]); video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]);
break; break;
} }
} else if (video->p->model == GB_MODEL_SGB) {
video->renderer->writeVideoRegister(video->renderer, address, value);
} else { } else {
switch (address) { switch (address) {
case REG_BCPD: case REG_BCPD:
@ -506,7 +550,12 @@ void GBVideoSetPalette(struct GBVideo* video, unsigned index, uint32_t color) {
} }
void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) { void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
switch (data[0] >> 3) { int i;
if (!(video->sgbCommandHeader & 7)) {
video->sgbCommandHeader = data[0];
}
--video->sgbCommandHeader;
switch (video->sgbCommandHeader >> 3) {
case SGB_PAL01: case SGB_PAL01:
video->palette[0] = data[1] | (data[2] << 8); video->palette[0] = data[1] | (data[2] << 8);
video->palette[1] = data[3] | (data[4] << 8); video->palette[1] = data[3] | (data[4] << 8);
@ -516,13 +565,17 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->palette[17] = data[9] | (data[10] << 8); video->palette[17] = data[9] | (data[10] << 8);
video->palette[18] = data[11] | (data[12] << 8); video->palette[18] = data[11] | (data[12] << 8);
video->palette[19] = data[13] | (data[14] << 8); video->palette[19] = data[13] | (data[14] << 8);
video->renderer->writePalette(video->renderer, 0, video->palette[0]); video->renderer->writePalette(video->renderer, 0, video->palette[0]);
video->renderer->writePalette(video->renderer, 1, video->palette[1]); video->renderer->writePalette(video->renderer, 1, video->palette[1]);
video->renderer->writePalette(video->renderer, 2, video->palette[2]); video->renderer->writePalette(video->renderer, 2, video->palette[2]);
video->renderer->writePalette(video->renderer, 3, video->palette[3]); video->renderer->writePalette(video->renderer, 3, video->palette[3]);
video->renderer->writePalette(video->renderer, 16, video->palette[0]);
video->renderer->writePalette(video->renderer, 17, video->palette[17]); video->renderer->writePalette(video->renderer, 17, video->palette[17]);
video->renderer->writePalette(video->renderer, 18, video->palette[18]); video->renderer->writePalette(video->renderer, 18, video->palette[18]);
video->renderer->writePalette(video->renderer, 19, video->palette[19]); video->renderer->writePalette(video->renderer, 19, video->palette[19]);
video->renderer->writePalette(video->renderer, 32, video->palette[0]);
video->renderer->writePalette(video->renderer, 48, video->palette[0]);
break; break;
case SGB_PAL23: case SGB_PAL23:
video->palette[32] = data[1] | (data[2] << 8); video->palette[32] = data[1] | (data[2] << 8);
@ -533,7 +586,6 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->palette[49] = data[9] | (data[10] << 8); video->palette[49] = data[9] | (data[10] << 8);
video->palette[50] = data[11] | (data[12] << 8); video->palette[50] = data[11] | (data[12] << 8);
video->palette[51] = data[13] | (data[14] << 8); video->palette[51] = data[13] | (data[14] << 8);
video->renderer->writePalette(video->renderer, 32, video->palette[32]);
video->renderer->writePalette(video->renderer, 33, video->palette[33]); video->renderer->writePalette(video->renderer, 33, video->palette[33]);
video->renderer->writePalette(video->renderer, 34, video->palette[34]); video->renderer->writePalette(video->renderer, 34, video->palette[34]);
video->renderer->writePalette(video->renderer, 35, video->palette[35]); video->renderer->writePalette(video->renderer, 35, video->palette[35]);
@ -547,6 +599,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->palette[2] = data[5] | (data[6] << 8); video->palette[2] = data[5] | (data[6] << 8);
video->palette[3] = data[7] | (data[8] << 8); video->palette[3] = data[7] | (data[8] << 8);
video->palette[48] = data[1] | (data[2] << 8);
video->palette[49] = data[9] | (data[10] << 8); video->palette[49] = data[9] | (data[10] << 8);
video->palette[50] = data[11] | (data[12] << 8); video->palette[50] = data[11] | (data[12] << 8);
video->palette[51] = data[13] | (data[14] << 8); video->palette[51] = data[13] | (data[14] << 8);
@ -554,6 +607,9 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->renderer->writePalette(video->renderer, 1, video->palette[1]); video->renderer->writePalette(video->renderer, 1, video->palette[1]);
video->renderer->writePalette(video->renderer, 2, video->palette[2]); video->renderer->writePalette(video->renderer, 2, video->palette[2]);
video->renderer->writePalette(video->renderer, 3, video->palette[3]); video->renderer->writePalette(video->renderer, 3, video->palette[3]);
video->renderer->writePalette(video->renderer, 16, video->palette[0]);
video->renderer->writePalette(video->renderer, 32, video->palette[0]);
video->renderer->writePalette(video->renderer, 48, video->palette[0]);
video->renderer->writePalette(video->renderer, 49, video->palette[49]); video->renderer->writePalette(video->renderer, 49, video->palette[49]);
video->renderer->writePalette(video->renderer, 50, video->palette[50]); video->renderer->writePalette(video->renderer, 50, video->palette[50]);
video->renderer->writePalette(video->renderer, 51, video->palette[51]); video->renderer->writePalette(video->renderer, 51, video->palette[51]);
@ -567,7 +623,6 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->palette[33] = data[9] | (data[10] << 8); video->palette[33] = data[9] | (data[10] << 8);
video->palette[34] = data[11] | (data[12] << 8); video->palette[34] = data[11] | (data[12] << 8);
video->palette[35] = data[13] | (data[14] << 8); video->palette[35] = data[13] | (data[14] << 8);
video->renderer->writePalette(video->renderer, 16, video->palette[16]);
video->renderer->writePalette(video->renderer, 17, video->palette[17]); video->renderer->writePalette(video->renderer, 17, video->palette[17]);
video->renderer->writePalette(video->renderer, 18, video->palette[18]); video->renderer->writePalette(video->renderer, 18, video->palette[18]);
video->renderer->writePalette(video->renderer, 19, video->palette[19]); video->renderer->writePalette(video->renderer, 19, video->palette[19]);
@ -575,19 +630,35 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
video->renderer->writePalette(video->renderer, 34, video->palette[34]); video->renderer->writePalette(video->renderer, 34, video->palette[34]);
video->renderer->writePalette(video->renderer, 35, video->palette[35]); video->renderer->writePalette(video->renderer, 35, video->palette[35]);
break; break;
case SGB_PAL_SET:
for (i = 0; i < 4; ++i) {
uint16_t entry = (data[2 + (i * 2)] << 8) | data[1 + (i * 2)];
if (entry >= 0x200) {
mLOG(GB, STUB, "Unimplemented SGB palette overflow: %03X", entry);
continue;
}
LOAD_16LE(video->palette[i * 4 + 0], entry * 8 + 0, video->renderer->sgbPalRam);
video->renderer->writePalette(video->renderer, i * 4 + 0, video->palette[0]);
LOAD_16LE(video->palette[i * 4 + 1], entry * 8 + 2, video->renderer->sgbPalRam);
video->renderer->writePalette(video->renderer, i * 4 + 1, video->palette[i * 4 + 1]);
LOAD_16LE(video->palette[i * 4 + 2], entry * 8 + 4, video->renderer->sgbPalRam);
video->renderer->writePalette(video->renderer, i * 4 + 2, video->palette[i * 4 + 2]);
LOAD_16LE(video->palette[i * 4 + 3], entry * 8 + 6, video->renderer->sgbPalRam);
video->renderer->writePalette(video->renderer, i * 4 + 3, video->palette[i * 4 + 3]);
}
break;
case SGB_ATTR_BLK:
case SGB_PAL_TRN:
case SGB_CHR_TRN:
case SGB_PCT_TRN:
case SGB_ATTR_TRN:
case SGB_ATTR_SET:
break;
case SGB_MLT_REG: case SGB_MLT_REG:
return; return;
case SGB_MASK_EN: case SGB_MASK_EN:
video->renderer->sgbRenderMode = data[1] & 0x3; video->renderer->sgbRenderMode = data[1] & 0x3;
break; break;
case SGB_PAL_TRN:
case SGB_CHR_TRN:
case SGB_PCT_TRN:
break;
case SGB_PAL_SET:
case SGB_ATTR_SET:
mLOG(GB, STUB, "Unimplemented SGB command: %02X", data[0] >> 3);
break;
default: default:
mLOG(GB, STUB, "Unimplemented SGB command: %02X", data[0] >> 3); mLOG(GB, STUB, "Unimplemented SGB command: %02X", data[0] >> 3);
return; return;

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/renderers/software-private.h" #include "gba/renderers/software-private.h"
#include <mgba/core/interface.h>
#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/gba.h>
#define MODE_2_COORD_OVERFLOW \ #define MODE_2_COORD_OVERFLOW \
@ -101,6 +102,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer
if (!mosaicWait) { if (!mosaicWait) {
LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram); LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram);
color = mColorFrom555(color);
#ifndef COLOR_16_BIT #ifndef COLOR_16_BIT
unsigned color32; unsigned color32;
color32 = 0; color32 = 0;

View File

@ -359,22 +359,7 @@ static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer,
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
#ifdef COLOR_16_BIT color_t color = mColorFrom555(value);
#ifdef COLOR_5_6_5
unsigned color = 0;
color |= (value & 0x001F) << 11;
color |= (value & 0x03E0) << 1;
color |= (value & 0x7C00) >> 10;
#else
unsigned color = value;
#endif
#else
unsigned color = 0;
color |= (value << 3) & 0xF8;
color |= (value << 6) & 0xF800;
color |= (value << 9) & 0xF80000;
color |= (color >> 5) & 0x070707;
#endif
softwareRenderer->normalPalette[address >> 1] = color; softwareRenderer->normalPalette[address >> 1] = color;
if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) { if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
softwareRenderer->variantPalette[address >> 1] = _brighten(color, softwareRenderer->bldy); softwareRenderer->variantPalette[address >> 1] = _brighten(color, softwareRenderer->bldy);

View File

@ -14,6 +14,8 @@
#define CXX_GUARD_START #define CXX_GUARD_START
#define CXX_GUARD_END #define CXX_GUARD_END
#define PYCPARSE
typedef int... time_t; typedef int... time_t;
typedef int... off_t; typedef int... off_t;
typedef ... va_list; typedef ... va_list;
@ -24,7 +26,6 @@ typedef ...* png_unknown_chunkp;
void free(void*); void free(void*);
#include <limits.h> #include <limits.h>
#undef const
#include "flags.h" #include "flags.h"

View File

@ -33,7 +33,7 @@ void mSDLGLCreate(struct mSDLRenderer* renderer) {
bool mSDLGLInit(struct mSDLRenderer* renderer) { bool mSDLGLInit(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer); mSDLGLCommonInit(renderer);
size_t size = toPow2(renderer->width) * renderer->height * BYTES_PER_PIXEL; size_t size = toPow2(renderer->width) * toPow2(renderer->height) * BYTES_PER_PIXEL;
renderer->outputBuffer = malloc(size); renderer->outputBuffer = malloc(size);
memset(renderer->outputBuffer, 0, size); memset(renderer->outputBuffer, 0, size);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, toPow2(renderer->width)); renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, toPow2(renderer->width));
@ -67,9 +67,9 @@ void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
renderer->player.windowUpdated = 0; renderer->player.windowUpdated = 0;
} }
#endif #endif
if (renderer->width != v->width || renderer->height != v->height) { }
renderer->gl.d.setDimensions(&renderer->gl.d, renderer->width, renderer->height); if (renderer->width != v->width || renderer->height != v->height) {
} v->setDimensions(v, renderer->width, renderer->height);
} }
if (mCoreSyncWaitFrameStart(&context->impl->sync)) { if (mCoreSyncWaitFrameStart(&context->impl->sync)) {

View File

@ -98,7 +98,7 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer); mSDLGLCommonInit(renderer);
#endif #endif
size_t size = toPow2(renderer->width) * renderer->height * BYTES_PER_PIXEL; size_t size = toPow2(renderer->width) * toPow2(renderer->height) * BYTES_PER_PIXEL;
#ifndef __APPLE__ #ifndef __APPLE__
renderer->outputBuffer = memalign(16, size); renderer->outputBuffer = memalign(16, size);
#else #else