GB: Super Game Boy borders

This commit is contained in:
Vicki Pfau 2017-08-01 19:01:44 -07:00
parent 55679df8fc
commit 36c1fb59be
24 changed files with 523 additions and 57 deletions

View File

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

View File

@ -44,6 +44,34 @@ enum GBIRQVector {
GB_VECTOR_KEYPAD = 0x60,
};
enum GBSGBCommand {
SGB_PAL01 = 0,
SGB_PAL23,
SGB_PAL03,
SGB_PAL12,
SGB_ATTR_BLK,
SGB_ATTR_LIN,
SGB_ATTR_DIV,
SGB_ATTR_CHR,
SGB_SOUND,
SGB_SOU_TRN,
SGB_PAL_SET,
SGB_PAL_TRN,
SGB_ATRC_EN,
SGB_TEST_EN,
SGB_PICON_EN,
SGB_DATA_SND,
SGB_DATA_TRN,
SGB_MLT_REG,
SGB_JUMP,
SGB_CHR_TRN,
SGB_PCT_TRN,
SGB_ATTR_TRN,
SGB_ATTR_SET,
SGB_MASK_EN,
SGB_OBJ_TRN
};
struct LR35902Core;
struct mCoreSync;
struct mAVStream;
@ -76,6 +104,10 @@ struct GB {
int32_t sramDirtAge;
bool sramMaskWriteback;
int sgbBit;
int currentSgbBits;
uint8_t sgbPacket[16];
struct mCoreCallbacksList coreCallbacks;
struct mAVStream* stream;

View File

@ -34,6 +34,9 @@ struct GBVideoSoftwareRenderer {
GBRegisterLCDC lcdc;
enum GBModel model;
int sgbTransfer;
uint8_t sgbPacket[16];
};
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);

View File

@ -30,7 +30,11 @@ enum {
GB_VIDEO_TOTAL_LENGTH = 70224,
GB_BASE_MAP = 0x1800,
GB_SIZE_MAP = 0x0400
GB_SIZE_MAP = 0x0400,
SGB_SIZE_CHAR_RAM = 0x2000,
SGB_SIZE_MAP_RAM = 0x1000,
SGB_SIZE_PAL_RAM = 0x1000
};
DECL_BITFIELD(GBObjAttributes, uint8_t);
@ -41,6 +45,13 @@ DECL_BIT(GBObjAttributes, XFlip, 5);
DECL_BIT(GBObjAttributes, YFlip, 6);
DECL_BIT(GBObjAttributes, Priority, 7);
DECL_BITFIELD(SGBBgAttributes, uint16_t);
DECL_BITS(SGBBgAttributes, Tile, 0, 10);
DECL_BITS(SGBBgAttributes, Palette, 10, 3);
DECL_BIT(SGBBgAttributes, Priority, 13);
DECL_BIT(SGBBgAttributes, XFlip, 14);
DECL_BIT(SGBBgAttributes, YFlip, 15);
struct GBObj {
uint8_t y;
uint8_t x;
@ -59,6 +70,7 @@ struct GBVideoRenderer {
void (*deinit)(struct GBVideoRenderer* renderer);
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
void (*writeSGBPacket)(struct GBVideoRenderer* renderer, uint8_t* data);
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value);
void (*writeOAM)(struct GBVideoRenderer* renderer, uint16_t oam);
@ -73,6 +85,11 @@ struct GBVideoRenderer {
union GBOAM* oam;
struct mTileCache* cache;
uint8_t* sgbCharRam;
uint8_t* sgbMapRam;
uint8_t* sgbPalRam;
int sgbRenderMode;
bool disableBG;
bool disableOBJ;
bool disableWIN;
@ -146,6 +163,8 @@ void GBVideoSwitchBank(struct GBVideo* video, uint8_t value);
void GBVideoSetPalette(struct GBVideo* video, unsigned index, uint32_t color);
void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data);
struct GBSerializedState;
void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state);
void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state);

View File

@ -190,9 +190,14 @@ static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* conf
}
static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
UNUSED(core);
struct GB* gb = core->board;
if (!gb || gb->model != GB_MODEL_SGB) {
*width = GB_VIDEO_HORIZONTAL_PIXELS;
*height = GB_VIDEO_VERTICAL_PIXELS;
} else {
*width = 256;
*height = 224;
}
}
static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {

View File

@ -10,10 +10,12 @@
#include <mgba/internal/gb/io.h>
#define BUFFER_OAM 1
#define BUFFER_SGB 2
static void GBVideoProxyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);
static void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer);
static uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoProxyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data);
static void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
static void GBVideoProxyRendererWritePalette(struct GBVideoRenderer* renderer, int address, uint16_t value);
@ -30,6 +32,7 @@ void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GB
renderer->d.init = GBVideoProxyRendererInit;
renderer->d.deinit = GBVideoProxyRendererDeinit;
renderer->d.writeVideoRegister = GBVideoProxyRendererWriteVideoRegister;
renderer->d.writeSGBPacket = GBVideoProxyRendererWriteSGBPacket;
renderer->d.writeVRAM = GBVideoProxyRendererWriteVRAM;
renderer->d.writeOAM = GBVideoProxyRendererWriteOAM;
renderer->d.writePalette = GBVideoProxyRendererWritePalette;
@ -111,6 +114,7 @@ void GBVideoProxyRendererDeinit(struct GBVideoRenderer* renderer) {
static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) {
struct GBVideoProxyRenderer* proxyRenderer = logger->context;
uint8_t sgbPacket[16];
switch (item->type) {
case DIRTY_REGISTER:
proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value);
@ -154,6 +158,11 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
return false;
}
logger->readData(logger, &proxyRenderer->objThisLine, item->value2, true);
break;
case BUFFER_SGB:
logger->readData(logger, sgbPacket, 16, true);
proxyRenderer->backend->writeSGBPacket(proxyRenderer->backend, sgbPacket);
break;
}
break;
case DIRTY_FLUSH:
@ -179,6 +188,14 @@ uint8_t GBVideoProxyRendererWriteVideoRegister(struct GBVideoRenderer* renderer,
return value;
}
void GBVideoProxyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) {
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
if (!proxyRenderer->logger->block) {
proxyRenderer->backend->writeSGBPacket(proxyRenderer->backend, data);
}
mVideoLoggerWriteBuffer(proxyRenderer->logger, BUFFER_SGB, 0, 16, data);
}
void GBVideoProxyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer;
mVideoLoggerRendererWriteVRAM(proxyRenderer->logger, address);

View File

@ -28,6 +28,7 @@ static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66};
#define DMG_BIOS_CHECKSUM 0xC2F5CC97
#define DMG_2_BIOS_CHECKSUM 0x59C8598E
#define SGB_BIOS_CHECKSUM 0xEC8A83B9
#define CGB_BIOS_CHECKSUM 0x41884E46
mLOG_DEFINE_CATEGORY(GB, "GB", "gb");
@ -384,6 +385,7 @@ bool GBIsBIOS(struct VFile* vf) {
switch (_GBBiosCRC32(vf)) {
case DMG_BIOS_CHECKSUM:
case DMG_2_BIOS_CHECKSUM:
case SGB_BIOS_CHECKSUM:
case CGB_BIOS_CHECKSUM:
return true;
default:
@ -425,11 +427,11 @@ void GBReset(struct LR35902Core* cpu) {
if (!gb->biosVf) {
switch (gb->model) {
case GB_MODEL_DMG:
// TODO: SGB
case GB_MODEL_SGB:
case GB_MODEL_AUTODETECT: // Silence warnings
gb->model = GB_MODEL_DMG;
// TODO: SGB registers
case GB_MODEL_SGB:
case GB_MODEL_DMG:
cpu->a = 1;
cpu->f.packed = 0xB0;
cpu->c = 0x13;
@ -467,6 +469,10 @@ void GBReset(struct LR35902Core* cpu) {
gb->yankedRomSize = 0;
}
gb->sgbBit = -1;
gb->currentSgbBits = 0;
memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
mTimingClear(&gb->timing);
GBMemoryReset(gb);
@ -491,6 +497,9 @@ void GBDetectModel(struct GB* gb) {
case DMG_2_BIOS_CHECKSUM:
gb->model = GB_MODEL_DMG;
break;
case SGB_BIOS_CHECKSUM:
gb->model = GB_MODEL_SGB;
break;
case CGB_BIOS_CHECKSUM:
gb->model = GB_MODEL_CGB;
break;
@ -503,6 +512,8 @@ void GBDetectModel(struct GB* gb) {
const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
if (cart->cgb & 0x80) {
gb->model = GB_MODEL_CGB;
} else if (cart->sgb == 0x03 && cart->oldLicensee == 0x33) {
gb->model = GB_MODEL_SGB;
} else {
gb->model = GB_MODEL_DMG;
}

View File

@ -105,6 +105,33 @@ static const uint8_t _registerMask[] = {
[REG_IE] = 0xE0,
};
static void _writeSGBBits(struct GB* gb, int bits) {
if (!bits) {
gb->sgbBit = 0;
memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
}
if (bits == gb->currentSgbBits) {
return;
}
gb->currentSgbBits = bits;
if (gb->sgbBit == 128 && bits == 2) {
GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
++gb->sgbBit;
}
if (gb->sgbBit >= 128) {
return;
}
switch (bits) {
case 1:
gb->sgbPacket[gb->sgbBit >> 3] |= 1 << (gb->sgbBit & 7);
// Fall through
case 2:
++gb->sgbBit;
default:
break;
}
}
void GBIOInit(struct GB* gb) {
memset(gb->memory.io, 0, sizeof(gb->memory.io));
}
@ -341,6 +368,10 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
}
break;
case REG_JOYP:
if (gb->model == GB_MODEL_SGB) {
_writeSGBBits(gb, (value >> 4) & 3);
}
break;
case REG_TIMA:
case REG_TMA:
// Handled transparently by the registers
@ -453,7 +484,8 @@ static uint8_t _readKeys(struct GB* gb) {
uint8_t keys = *gb->keySource;
switch (gb->memory.io[REG_JOYP] & 0x30) {
case 0x30:
keys = 0;
// TODO: Increment
keys = gb->model == GB_MODEL_SGB ? 0xF : 0;
break;
case 0x20:
keys >>= 4;

View File

@ -54,7 +54,7 @@ bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverri
override->model = GB_MODEL_AGB;
} else if (strcasecmp(model, "SGB") == 0) {
found = true;
override->model = GB_MODEL_DMG; // TODO
override->model = GB_MODEL_SGB;
} else if (strcasecmp(model, "MGB") == 0) {
found = true;
override->model = GB_MODEL_DMG; // TODO

View File

@ -7,11 +7,13 @@
#include <mgba/core/tile-cache.h>
#include <mgba/internal/gb/io.h>
#include <mgba-util/math.h>
#include <mgba-util/memory.h>
static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data);
static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value);
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
@ -25,9 +27,13 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y);
static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) {
size_t sgbOffset = 0;
if (renderer->model == GB_MODEL_SGB) {
sgbOffset = renderer->outputBufferStride * 40 + 48;
}
int y;
for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) {
color_t* row = &renderer->outputBuffer[renderer->outputBufferStride * y];
color_t* row = &renderer->outputBuffer[renderer->outputBufferStride * y + sgbOffset];
int x;
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 4) {
row[x + 0] = renderer->palette[0];
@ -38,10 +44,64 @@ static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) {
}
}
static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
int i;
for (i = 0; i < 0x40; ++i) {
uint16_t color;
LOAD_16LE(color, 0x800 + i * 2, renderer->d.sgbMapRam);
renderer->d.writePalette(&renderer->d, i + 0x40, color);
}
int x, y;
for (y = 0; y < 224; ++y) {
for (x = 0; x < 256; x += 8) {
uint16_t mapData;
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
if (UNLIKELY(SGBBgAttributesGetTile(mapData) > 0x100)) {
continue;
}
int localY = y & 0x7;
if (SGBBgAttributesIsYFlip(mapData)) {
localY = 7 - y;
}
uint8_t tileData[4];
tileData[0] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x00];
tileData[1] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x01];
tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10];
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;
int p = SGBBgAttributesGetPalette(mapData) * 0x10;
if (SGBBgAttributesIsXFlip(mapData)) {
renderer->outputBuffer[base + 0] = renderer->palette[p | ((tileData[0] >> 0) & 0x1) | ((tileData[1] << 1) & 0x2) | ((tileData[2] << 2) & 0x4) | ((tileData[3] << 3) & 0x8)];
renderer->outputBuffer[base + 1] = renderer->palette[p | ((tileData[0] >> 1) & 0x1) | ((tileData[1] >> 0) & 0x2) | ((tileData[2] << 1) & 0x4) | ((tileData[3] << 2) & 0x8)];
renderer->outputBuffer[base + 2] = renderer->palette[p | ((tileData[0] >> 2) & 0x1) | ((tileData[1] >> 1) & 0x2) | ((tileData[2] >> 0) & 0x4) | ((tileData[3] << 1) & 0x8)];
renderer->outputBuffer[base + 3] = renderer->palette[p | ((tileData[0] >> 3) & 0x1) | ((tileData[1] >> 2) & 0x2) | ((tileData[2] >> 1) & 0x4) | ((tileData[3] >> 0) & 0x8)];
renderer->outputBuffer[base + 4] = renderer->palette[p | ((tileData[0] >> 4) & 0x1) | ((tileData[1] >> 3) & 0x2) | ((tileData[2] >> 2) & 0x4) | ((tileData[3] >> 1) & 0x8)];
renderer->outputBuffer[base + 5] = renderer->palette[p | ((tileData[0] >> 5) & 0x1) | ((tileData[1] >> 4) & 0x2) | ((tileData[2] >> 3) & 0x4) | ((tileData[3] >> 2) & 0x8)];
renderer->outputBuffer[base + 6] = renderer->palette[p | ((tileData[0] >> 6) & 0x1) | ((tileData[1] >> 5) & 0x2) | ((tileData[2] >> 4) & 0x4) | ((tileData[3] >> 3) & 0x8)];
renderer->outputBuffer[base + 7] = renderer->palette[p | ((tileData[0] >> 7) & 0x1) | ((tileData[1] >> 6) & 0x2) | ((tileData[2] >> 5) & 0x4) | ((tileData[3] >> 4) & 0x8)];
} else {
renderer->outputBuffer[base + 0] = renderer->palette[p | ((tileData[0] >> 7) & 0x1) | ((tileData[1] >> 6) & 0x2) | ((tileData[2] >> 5) & 0x4) | ((tileData[3] >> 4) & 0x8)];
renderer->outputBuffer[base + 1] = renderer->palette[p | ((tileData[0] >> 6) & 0x1) | ((tileData[1] >> 5) & 0x2) | ((tileData[2] >> 4) & 0x4) | ((tileData[3] >> 3) & 0x8)];
renderer->outputBuffer[base + 2] = renderer->palette[p | ((tileData[0] >> 5) & 0x1) | ((tileData[1] >> 4) & 0x2) | ((tileData[2] >> 3) & 0x4) | ((tileData[3] >> 2) & 0x8)];
renderer->outputBuffer[base + 3] = renderer->palette[p | ((tileData[0] >> 4) & 0x1) | ((tileData[1] >> 3) & 0x2) | ((tileData[2] >> 2) & 0x4) | ((tileData[3] >> 1) & 0x8)];
renderer->outputBuffer[base + 4] = renderer->palette[p | ((tileData[0] >> 3) & 0x1) | ((tileData[1] >> 2) & 0x2) | ((tileData[2] >> 1) & 0x4) | ((tileData[3] >> 0) & 0x8)];
renderer->outputBuffer[base + 5] = renderer->palette[p | ((tileData[0] >> 2) & 0x1) | ((tileData[1] >> 1) & 0x2) | ((tileData[2] >> 0) & 0x4) | ((tileData[3] << 1) & 0x8)];
renderer->outputBuffer[base + 6] = renderer->palette[p | ((tileData[0] >> 1) & 0x1) | ((tileData[1] >> 0) & 0x2) | ((tileData[2] << 1) & 0x4) | ((tileData[3] << 2) & 0x8)];
renderer->outputBuffer[base + 7] = renderer->palette[p | ((tileData[0] >> 0) & 0x1) | ((tileData[1] << 1) & 0x2) | ((tileData[2] << 2) & 0x4) | ((tileData[3] << 3) & 0x8)];
}
}
}
}
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
renderer->d.init = GBVideoSoftwareRendererInit;
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
renderer->d.writeSGBPacket = GBVideoSoftwareRendererWriteSGBPacket;
renderer->d.writePalette = GBVideoSoftwareRendererWritePalette;
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
renderer->d.writeOAM = GBVideoSoftwareRendererWriteOAM;
@ -67,6 +127,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
softwareRenderer->currentWy = 0;
softwareRenderer->wx = 0;
softwareRenderer->model = model;
softwareRenderer->sgbTransfer = 0;
}
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
@ -96,6 +157,11 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
return value;
}
static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
memcpy(softwareRenderer->sgbPacket, data, sizeof(softwareRenderer->sgbPacket));
}
static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
#ifdef COLOR_16_BIT
@ -167,8 +233,14 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
GBVideoSoftwareRendererDrawObj(softwareRenderer, &obj[i], startX, endX, y);
}
}
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
size_t sgbOffset = 0;
if (softwareRenderer->model == GB_MODEL_SGB) {
sgbOffset = softwareRenderer->outputBufferStride * 40 + 48;
}
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y + sgbOffset];
int x;
switch (softwareRenderer->d.sgbRenderMode) {
case 0:
for (x = startX; x + 7 < (endX & ~7); x += 8) {
row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F];
row[x + 1] = softwareRenderer->palette[softwareRenderer->row[x + 1] & 0x7F];
@ -182,6 +254,40 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
for (; x < endX; ++x) {
row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F];
}
break;
case 1:
return;
case 2:
for (x = startX; x + 7 < (endX & ~7); x += 8) {
row[x] = 0;
row[x + 1] = 0;
row[x + 2] = 0;
row[x + 3] = 0;
row[x + 4] = 0;
row[x + 5] = 0;
row[x + 6] = 0;
row[x + 7] = 0;
}
for (; x < endX; ++x) {
row[x] = 0;
}
return;
case 3:
for (x = startX; x + 7 < (endX & ~7); x += 8) {
row[x] = softwareRenderer->palette[0];
row[x + 1] = softwareRenderer->palette[0];
row[x + 2] = softwareRenderer->palette[0];
row[x + 3] = softwareRenderer->palette[0];
row[x + 4] = softwareRenderer->palette[0];
row[x + 5] = softwareRenderer->palette[0];
row[x + 6] = softwareRenderer->palette[0];
row[x + 7] = softwareRenderer->palette[0];
}
for (; x < endX; ++x) {
row[x] = softwareRenderer->palette[0];
}
return;
}
}
static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) {
@ -189,6 +295,53 @@ static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* render
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && softwareRenderer->wx - 7 < GB_VIDEO_HORIZONTAL_PIXELS) {
++softwareRenderer->currentWy;
}
if (softwareRenderer->sgbTransfer == 1) {
uint8_t* buffer = NULL;
switch (softwareRenderer->sgbPacket[0] >> 3) {
case SGB_PAL_TRN:
buffer = renderer->sgbPalRam;
break;
case SGB_CHR_TRN:
buffer = &renderer->sgbCharRam[SGB_SIZE_CHAR_RAM / 2 * (softwareRenderer->sgbPacket[1] & 1)];
break;
case SGB_PCT_TRN:
buffer = renderer->sgbMapRam;
break;
default:
break;
}
if (buffer) {
size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS);
if (offset < 0x1000) {
int i;
for (i = 0; i < GB_VIDEO_HORIZONTAL_PIXELS; i += 8) {
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;
}
}
}
}
}
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
@ -201,6 +354,34 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
if (!GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) {
_clearScreen(softwareRenderer);
}
if (softwareRenderer->model == GB_MODEL_SGB) {
switch (softwareRenderer->sgbPacket[0] >> 3) {
case SGB_PAL_SET:
if (softwareRenderer->sgbPacket[9] & 0x40) {
renderer->sgbRenderMode = 0;
}
break;
case SGB_ATTR_SET:
if (softwareRenderer->sgbPacket[1] & 0x40) {
renderer->sgbRenderMode = 0;
}
break;
case SGB_PAL_TRN:
case SGB_CHR_TRN:
case SGB_PCT_TRN:
if (softwareRenderer->sgbTransfer > 0) {
// Make sure every buffer sees this if we're multibuffering
_regenerateSGBBorder(softwareRenderer);
}
++softwareRenderer->sgbTransfer;
if (softwareRenderer->sgbTransfer == 5) {
softwareRenderer->sgbTransfer = 0;
softwareRenderer->sgbPacket[0] = 0;
}
default:
break;
}
}
softwareRenderer->currentWy = 0;
}

View File

@ -18,6 +18,7 @@
static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model);
static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoDummyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data);
static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value);
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam);
@ -39,6 +40,7 @@ static struct GBVideoRenderer dummyRenderer = {
.init = GBVideoDummyRendererInit,
.deinit = GBVideoDummyRendererDeinit,
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
.writeSGBPacket = GBVideoDummyRendererWriteSGBPacket,
.writeVRAM = GBVideoDummyRendererWriteVRAM,
.writeOAM = GBVideoDummyRendererWriteOAM,
.writePalette = GBVideoDummyRendererWritePalette,
@ -52,6 +54,7 @@ static struct GBVideoRenderer dummyRenderer = {
void GBVideoInit(struct GBVideo* video) {
video->renderer = &dummyRenderer;
video->renderer->cache = NULL;
video->renderer->sgbRenderMode = 0;
video->vram = 0;
video->frameskip = 0;
@ -68,6 +71,10 @@ void GBVideoInit(struct GBVideo* video) {
video->dmgPalette[1] = 0x56B5;
video->dmgPalette[2] = 0x294A;
video->dmgPalette[3] = 0x0000;
video->renderer->sgbCharRam = NULL;
video->renderer->sgbMapRam = NULL;
video->renderer->sgbPalRam = NULL;
}
void GBVideoReset(struct GBVideo* video) {
@ -89,6 +96,12 @@ void GBVideoReset(struct GBVideo* video) {
video->renderer->oam = &video->oam;
memset(&video->palette, 0, sizeof(video->palette));
if (video->p->model == GB_MODEL_SGB) {
video->renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM);
video->renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM);
video->renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);
}
video->renderer->deinit(video->renderer);
video->renderer->init(video->renderer, video->p->model);
}
@ -96,11 +109,27 @@ void GBVideoReset(struct GBVideo* video) {
void GBVideoDeinit(struct GBVideo* video) {
GBVideoAssociateRenderer(video, &dummyRenderer);
mappedMemoryFree(video->vram, GB_SIZE_VRAM);
if (video->renderer->sgbCharRam) {
mappedMemoryFree(video->renderer->sgbCharRam, SGB_SIZE_CHAR_RAM);
video->renderer->sgbCharRam = NULL;
}
if (video->renderer->sgbMapRam) {
mappedMemoryFree(video->renderer->sgbMapRam, SGB_SIZE_MAP_RAM);
video->renderer->sgbMapRam = NULL;
}
if (video->renderer->sgbPalRam) {
mappedMemoryFree(video->renderer->sgbPalRam, SGB_SIZE_PAL_RAM);
video->renderer->sgbPalRam = NULL;
}
}
void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) {
video->renderer->deinit(video->renderer);
renderer->cache = video->renderer->cache;
renderer->sgbRenderMode = video->renderer->sgbRenderMode;
renderer->sgbCharRam = video->renderer->sgbCharRam;
renderer->sgbMapRam = video->renderer->sgbMapRam;
renderer->sgbPalRam = video->renderer->sgbPalRam;
video->renderer = renderer;
renderer->vram = video->vram;
video->renderer->init(video->renderer, video->p->model);
@ -372,7 +401,7 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) {
GBRegisterSTAT oldStat = video->stat;
video->stat = (video->stat & 0x7) | (value & 0x78);
if (video->p->model == GB_MODEL_DMG && !_statIRQAsserted(video, oldStat) && video->mode < 3) {
if (video->p->model < GB_MODEL_CGB && !_statIRQAsserted(video, oldStat) && video->mode < 3) {
// TODO: variable for the IRQ line value?
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p);
@ -476,6 +505,96 @@ void GBVideoSetPalette(struct GBVideo* video, unsigned index, uint32_t color) {
video->dmgPalette[index] = M_RGB8_TO_RGB5(color);
}
void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
switch (data[0] >> 3) {
case SGB_PAL01:
video->palette[0] = data[1] | (data[2] << 8);
video->palette[1] = data[3] | (data[4] << 8);
video->palette[2] = data[5] | (data[6] << 8);
video->palette[3] = data[7] | (data[8] << 8);
video->palette[17] = data[9] | (data[10] << 8);
video->palette[18] = data[11] | (data[12] << 8);
video->palette[19] = data[13] | (data[14] << 8);
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, 17, video->palette[17]);
video->renderer->writePalette(video->renderer, 18, video->palette[18]);
video->renderer->writePalette(video->renderer, 19, video->palette[19]);
break;
case SGB_PAL23:
video->palette[32] = data[1] | (data[2] << 8);
video->palette[33] = data[3] | (data[4] << 8);
video->palette[34] = data[5] | (data[6] << 8);
video->palette[35] = data[7] | (data[8] << 8);
video->palette[49] = data[9] | (data[10] << 8);
video->palette[50] = data[11] | (data[12] << 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, 34, video->palette[34]);
video->renderer->writePalette(video->renderer, 35, video->palette[35]);
video->renderer->writePalette(video->renderer, 49, video->palette[49]);
video->renderer->writePalette(video->renderer, 50, video->palette[50]);
video->renderer->writePalette(video->renderer, 51, video->palette[51]);
break;
case SGB_PAL03:
video->palette[0] = data[1] | (data[2] << 8);
video->palette[1] = data[3] | (data[4] << 8);
video->palette[2] = data[5] | (data[6] << 8);
video->palette[3] = data[7] | (data[8] << 8);
video->palette[49] = data[9] | (data[10] << 8);
video->palette[50] = data[11] | (data[12] << 8);
video->palette[51] = data[13] | (data[14] << 8);
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, 49, video->palette[49]);
video->renderer->writePalette(video->renderer, 50, video->palette[50]);
video->renderer->writePalette(video->renderer, 51, video->palette[51]);
break;
case SGB_PAL12:
video->palette[16] = data[1] | (data[2] << 8);
video->palette[17] = data[3] | (data[4] << 8);
video->palette[18] = data[5] | (data[6] << 8);
video->palette[19] = data[7] | (data[8] << 8);
video->palette[33] = data[9] | (data[10] << 8);
video->palette[34] = data[11] | (data[12] << 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, 18, video->palette[18]);
video->renderer->writePalette(video->renderer, 19, video->palette[19]);
video->renderer->writePalette(video->renderer, 33, video->palette[33]);
video->renderer->writePalette(video->renderer, 34, video->palette[34]);
video->renderer->writePalette(video->renderer, 35, video->palette[35]);
break;
case SGB_MLT_REG:
return;
case SGB_MASK_EN:
video->renderer->sgbRenderMode = data[1] & 0x3;
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:
mLOG(GB, STUB, "Unimplemented SGB command: %02X", data[0] >> 3);
return;
}
video->renderer->writeSGBPacket(video->renderer, data);
}
static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model) {
UNUSED(renderer);
UNUSED(model);
@ -493,6 +612,11 @@ static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* re
return value;
}
static void GBVideoDummyRendererWriteSGBPacket(struct GBVideoRenderer* renderer, uint8_t* data) {
UNUSED(renderer);
UNUSED(data);
}
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
if (renderer->cache) {
mTileCacheWriteVRAM(renderer->cache, address);

View File

@ -285,7 +285,7 @@ static void _setup(struct mGUIRunner* runner) {
_map3DSKey(&runner->core->inputMap, KEY_L, GBA_KEY_L);
_map3DSKey(&runner->core->inputMap, KEY_R, GBA_KEY_R);
outputBuffer = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * 2, 0x80);
outputBuffer = linearMemAlign(256 * 224 * 2, 0x80);
runner->core->setVideoBuffer(runner->core, outputBuffer, 256);
unsigned mode;

View File

@ -390,7 +390,7 @@ bool retro_load_game(const struct retro_game_info* game) {
core->init(core);
core->setAVStream(core, &stream);
outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
outputBuffer = malloc(256 * 224 * BYTES_PER_PIXEL);
core->setVideoBuffer(core, outputBuffer, 256);
core->setAudioBufferSize(core, SAMPLES);

View File

@ -65,13 +65,9 @@
};
mCoreConfigLoadDefaults(&core->config, &opts);
core->init(core);
outputBuffer = nil;
unsigned width, height;
core->desiredVideoDimensions(core, &width, &height);
outputBuffer = malloc(width * height * BYTES_PER_PIXEL);
core->setVideoBuffer(core, outputBuffer, width);
core->setAudioBufferSize(core, SAMPLES);
cheatSets = [[NSMutableDictionary alloc] init];
}
@ -108,6 +104,15 @@
mCoreAutoloadSave(core);
core->reset(core);
unsigned width, height;
core->desiredVideoDimensions(core, &width, &height);
if (outputBuffer) {
free(outputBuffer);
}
outputBuffer = malloc(width * height * BYTES_PER_PIXEL);
core->setVideoBuffer(core, outputBuffer, width);
return YES;
}

View File

@ -110,12 +110,12 @@ void mGLContextPostFrame(struct VideoBackend* v, const void* frame) {
glBindTexture(GL_TEXTURE_2D, context->tex);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, toPow2(v->width), v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, toPow2(v->width), v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, toPow2(v->width), v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif
}

View File

@ -8,6 +8,7 @@
#include <mgba/core/log.h>
#include <mgba-util/configuration.h>
#include <mgba-util/formatting.h>
#include <mgba-util/math.h>
#include <mgba-util/vector.h>
#include <mgba-util/vfs.h>
@ -190,13 +191,6 @@ static void mGLES2ContextClear(struct VideoBackend* v) {
void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
GLint viewport[4];
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
if (shader->blend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT);
}
glGetIntegerv(GL_VIEWPORT, viewport);
int drawW = shader->width;
@ -222,6 +216,14 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
drawH -= drawH % context->d.height;
}
glViewport(padW, padH, drawW, drawH);
if (shader->blend) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT);
}
if (shader->tex && (shader->width <= 0 || shader->height <= 0)) {
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
@ -316,6 +318,7 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) {
void mGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
glBindTexture(GL_TEXTURE_2D, context->tex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, toPow2(v->width));
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);

View File

@ -25,6 +25,7 @@
#include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/renderers/tile-cache.h>
#endif
#include <mgba-util/math.h>
#include <mgba-util/vfs.h>
using namespace QGBA;
@ -38,9 +39,11 @@ CoreController::CoreController(mCore* core, QObject* parent)
m_threadContext.core = core;
m_threadContext.userData = this;
QSize size = screenDimensions();
m_buffers[0].resize(size.width() * size.height() * sizeof(color_t));
m_buffers[1].resize(size.width() * size.height() * sizeof(color_t));
QSize size(256, 512);
m_buffers[0].resize(toPow2(size.width()) * size.height() * sizeof(color_t));
m_buffers[1].resize(toPow2(size.width()) * size.height() * sizeof(color_t));
m_buffers[0].fill(0xFF);
m_buffers[1].fill(0xFF);
m_activeBuffer = &m_buffers[0];
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), size.width());
@ -81,7 +84,15 @@ CoreController::CoreController(mCore* core, QObject* parent)
}
controller->m_resetActions.clear();
controller->m_activeBuffer->fill(0xFF);
QSize size = controller->screenDimensions();
controller->m_buffers[0].resize(toPow2(size.width()) * size.height() * sizeof(color_t));
controller->m_buffers[1].resize(toPow2(size.width()) * size.height() * sizeof(color_t));
controller->m_buffers[0].fill(0xFF);
controller->m_buffers[1].fill(0xFF);
controller->m_activeBuffer = &controller->m_buffers[0];
context->core->setVideoBuffer(context->core, reinterpret_cast<color_t*>(controller->m_activeBuffer->data()), toPow2(size.width()));
controller->finishFrame();
};
@ -712,7 +723,7 @@ void CoreController::finishFrame() {
if (m_activeBuffer == m_completeBuffer) {
m_activeBuffer = &m_buffers[1];
}
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), screenDimensions().width());
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), toPow2(screenDimensions().width()));
for (auto& action : m_frameActions) {
action();

View File

@ -14,6 +14,7 @@
#include <QTimer>
#include <mgba/core/core.h>
#include <mgba-util/math.h>
#ifdef BUILD_GL
#include "platform/opengl/gl.h"
#endif
@ -390,7 +391,7 @@ void PainterGL::enqueue(const uint32_t* backing) {
buffer = m_free.takeLast();
}
QSize size = m_context->screenDimensions();
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
memcpy(buffer, backing, toPow2(size.width()) * size.height() * BYTES_PER_PIXEL);
m_queue.enqueue(buffer);
m_mutex.unlock();
}

View File

@ -11,6 +11,7 @@
#include <mgba/core/core.h>
#include <mgba/core/thread.h>
#include <mgba-util/math.h>
using namespace QGBA;
@ -56,12 +57,12 @@ void DisplayQt::framePosted() {
}
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB16);
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), toPow2(m_width), m_height, QImage::Format_RGB16);
#else
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB555);
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), toPow2(m_width), m_height, QImage::Format_RGB555);
#endif
#else
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_ARGB32);
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), toPow2(m_width), m_height, QImage::Format_ARGB32);
m_backing = m_backing.convertToFormat(QImage::Format_RGB32);
#endif
}

View File

@ -51,6 +51,7 @@ OverrideView::OverrideView(ConfigController* config, QWidget* parent)
// NB: Keep in sync with OverrideView.ui
s_gbModelList.append(GB_MODEL_AUTODETECT);
s_gbModelList.append(GB_MODEL_DMG);
s_gbModelList.append(GB_MODEL_SGB);
s_gbModelList.append(GB_MODEL_CGB);
s_gbModelList.append(GB_MODEL_AGB);
}

View File

@ -253,6 +253,11 @@
<string>Game Boy (DMG)</string>
</property>
</item>
<item>
<property name="text">
<string>Super Game Boy (SGB)</string>
</property>
</item>
<item>
<property name="text">
<string>Game Boy Color (CGB)</string>

View File

@ -9,6 +9,8 @@
#include <mgba/core/core.h>
#include <mgba/core/thread.h>
#include <mgba-util/math.h>
#include "platform/opengl/gl.h"
static void _doViewport(int w, int h, struct VideoBackend* v) {
@ -31,9 +33,10 @@ void mSDLGLCreate(struct mSDLRenderer* renderer) {
bool mSDLGLInit(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
renderer->outputBuffer = malloc(renderer->width * renderer->height * BYTES_PER_PIXEL);
memset(renderer->outputBuffer, 0, renderer->width * renderer->height * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
size_t size = toPow2(renderer->width) * renderer->height * BYTES_PER_PIXEL;
renderer->outputBuffer = malloc(size);
memset(renderer->outputBuffer, 0, size);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, toPow2(renderer->width));
mGLContextCreate(&renderer->gl);
renderer->gl.d.user = renderer;
@ -64,6 +67,9 @@ void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
renderer->player.windowUpdated = 0;
}
#endif
if (renderer->width != v->width || renderer->height != v->height) {
renderer->gl.d.setDimensions(&renderer->gl.d, renderer->width, renderer->height);
}
}
if (mCoreSyncWaitFrameStart(&context->impl->sync)) {

View File

@ -98,13 +98,14 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer);
#endif
size_t size = toPow2(renderer->width) * renderer->height * BYTES_PER_PIXEL;
#ifndef __APPLE__
renderer->outputBuffer = memalign(16, renderer->width * renderer->height * BYTES_PER_PIXEL);
renderer->outputBuffer = memalign(16, size);
#else
posix_memalign((void**) &renderer->outputBuffer, 16, renderer->width * renderer->height * BYTES_PER_PIXEL);
posix_memalign((void**) &renderer->outputBuffer, 16, size);
#endif
memset(renderer->outputBuffer, 0, renderer->width * renderer->height * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
memset(renderer->outputBuffer, 0, size);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, toPow2(renderer->width));
mGLES2ContextCreate(&renderer->gl2);
renderer->gl2.d.user = renderer;

View File

@ -220,6 +220,13 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
bool didFail = !mCoreThreadStart(&thread);
if (!didFail) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
renderer->core->desiredVideoDimensions(renderer->core, &renderer->width, &renderer->height);
unsigned width = renderer->width * renderer->ratio;
unsigned height = renderer->height * renderer->ratio;
if (width != (unsigned) renderer->viewportWidth && height != (unsigned) renderer->viewportHeight) {
SDL_SetWindowSize(renderer->window, width, height);
renderer->player.windowUpdated = 1;
}
mSDLSetScreensaverSuspendable(&renderer->events, renderer->core->opts.suspendScreensaver);
mSDLSuspendScreensaver(&renderer->events);
#endif