diff --git a/include/mgba/internal/ds/renderers/software.h b/include/mgba/internal/ds/renderers/software.h index 34beecd37..89aad89ea 100644 --- a/include/mgba/internal/ds/renderers/software.h +++ b/include/mgba/internal/ds/renderers/software.h @@ -19,6 +19,9 @@ struct DSVideoSoftwareRenderer { struct GBAVideoSoftwareRenderer engA; struct GBAVideoSoftwareRenderer engB; + DSRegisterDISPCNT dispcntA; + DSRegisterDISPCNT dispcntB; + color_t* outputBuffer; int outputBufferStride; diff --git a/include/mgba/internal/ds/video.h b/include/mgba/internal/ds/video.h index eecc67bd5..0618bd045 100644 --- a/include/mgba/internal/ds/video.h +++ b/include/mgba/internal/ds/video.h @@ -35,12 +35,32 @@ union DSOAM { uint16_t raw[1024]; }; +DECL_BITFIELD(DSRegisterDISPCNT, uint32_t); +DECL_BITS(DSRegisterDISPCNT, Mode, 0, 3); +DECL_BIT(DSRegisterDISPCNT, 3D, 3); +DECL_BIT(DSRegisterDISPCNT, TileObjMapping, 4); +DECL_BIT(DSRegisterDISPCNT, BitmapObj2D, 5); +DECL_BIT(DSRegisterDISPCNT, BitmapObjMapping, 6); +DECL_BIT(DSRegisterDISPCNT, ForcedBlank, 7); +DECL_BIT(DSRegisterDISPCNT, Bg0Enable, 8); +DECL_BIT(DSRegisterDISPCNT, Bg1Enable, 9); +DECL_BIT(DSRegisterDISPCNT, Bg2Enable, 10); +DECL_BIT(DSRegisterDISPCNT, Bg3Enable, 11); +DECL_BIT(DSRegisterDISPCNT, ObjEnable, 12); +DECL_BIT(DSRegisterDISPCNT, Win0Enable, 13); +DECL_BIT(DSRegisterDISPCNT, Win1Enable, 14); +DECL_BIT(DSRegisterDISPCNT, ObjwinEnable, 15); +DECL_BITS(DSRegisterDISPCNT, DispMode, 16, 2); +DECL_BITS(DSRegisterDISPCNT, VRAMBlock, 18, 2); +// TODO + struct DSVideoRenderer { void (*init)(struct DSVideoRenderer* renderer); void (*reset)(struct DSVideoRenderer* renderer); void (*deinit)(struct DSVideoRenderer* renderer); uint16_t (*writeVideoRegister)(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); + void (*writePalette)(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); void (*drawScanline)(struct DSVideoRenderer* renderer, int y); void (*finishFrame)(struct DSVideoRenderer* renderer); @@ -49,6 +69,10 @@ struct DSVideoRenderer { uint16_t* palette; uint16_t* vram; + uint16_t* vramABG[32]; + uint16_t* vramAOBJ[32]; + uint16_t* vramBBG[32]; + uint16_t* vramBOBJ[32]; union DSOAM* oam; }; @@ -64,6 +88,10 @@ struct DSVideo { uint16_t palette[1024]; uint16_t* vram; + uint16_t* vramABG[32]; + uint16_t* vramAOBJ[32]; + uint16_t* vramBBG[32]; + uint16_t* vramBOBJ[32]; union DSOAM oam; int32_t frameCounter; @@ -80,7 +108,7 @@ struct DSCommon; void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value); struct DSMemory; -void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value); +void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value); CXX_GUARD_START diff --git a/src/ds/io.c b/src/ds/io.c index 3bd5b25b1..3c3c1725f 100644 --- a/src/ds/io.c +++ b/src/ds/io.c @@ -386,9 +386,9 @@ void DS9IOInit(struct DS* ds) { } void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) { - if (address <= DS9_REG_A_BLDY && (address > DS_REG_VCOUNT || address == DS9_REG_A_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) { + if (address <= DS9_REG_A_BLDY && (address > DS_REG_VCOUNT || address == DS9_REG_A_DISPCNT_LO || address == DS9_REG_A_DISPCNT_HI)) { value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value); - } else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY && (address == DS9_REG_B_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) { + } else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) { value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value); } else { switch (address) { @@ -397,18 +397,18 @@ void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) { case DS9_REG_VRAMCNT_C: case DS9_REG_VRAMCNT_E: value &= 0x9F9F; - DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value & 0xFF); - DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value >> 8); + DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A, value & 0xFF); + DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A + 1, value >> 8); break; case DS9_REG_VRAMCNT_G: value &= 0x9F03; - DSVideoConfigureVRAM(&ds->memory, 6, value & 0xFF); + DSVideoConfigureVRAM(ds, 6, value & 0xFF); DSConfigureWRAM(&ds->memory, value >> 8); break; case DS9_REG_VRAMCNT_H: value &= 0x9F9F; - DSVideoConfigureVRAM(&ds->memory, 7, value & 0xFF); - DSVideoConfigureVRAM(&ds->memory, 8, value >> 8); + DSVideoConfigureVRAM(ds, 7, value & 0xFF); + DSVideoConfigureVRAM(ds, 8, value >> 8); break; case DS9_REG_EXMEMCNT: diff --git a/src/ds/memory.c b/src/ds/memory.c index cd43d2a22..ab0de0466 100644 --- a/src/ds/memory.c +++ b/src/ds/memory.c @@ -181,15 +181,15 @@ void DSMemoryReset(struct DS* ds) { ds->ds7.memory.slot1Access = true; ds->ds9.memory.slot1Access = false; - DSVideoConfigureVRAM(&ds->memory, 0, 0); - DSVideoConfigureVRAM(&ds->memory, 1, 0); - DSVideoConfigureVRAM(&ds->memory, 2, 0); - DSVideoConfigureVRAM(&ds->memory, 3, 0); - DSVideoConfigureVRAM(&ds->memory, 4, 0); - DSVideoConfigureVRAM(&ds->memory, 5, 0); - DSVideoConfigureVRAM(&ds->memory, 6, 0); - DSVideoConfigureVRAM(&ds->memory, 7, 0); - DSVideoConfigureVRAM(&ds->memory, 8, 0); + DSVideoConfigureVRAM(ds, 0, 0); + DSVideoConfigureVRAM(ds, 1, 0); + DSVideoConfigureVRAM(ds, 2, 0); + DSVideoConfigureVRAM(ds, 3, 0); + DSVideoConfigureVRAM(ds, 4, 0); + DSVideoConfigureVRAM(ds, 5, 0); + DSVideoConfigureVRAM(ds, 6, 0); + DSVideoConfigureVRAM(ds, 7, 0); + DSVideoConfigureVRAM(ds, 8, 0); DSConfigureWRAM(&ds->memory, 3); if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) { @@ -940,6 +940,8 @@ void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle break; case DS9_REGION_PALETTE_RAM: STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette); + ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16); + ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value); break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); @@ -1006,6 +1008,7 @@ void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle break; case DS9_REGION_PALETTE_RAM: STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette); + ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 2), value); break; case DS_REGION_VRAM: { unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); @@ -1228,7 +1231,9 @@ uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum }); break; case DS9_REGION_PALETTE_RAM: - STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette)); + STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette); + ds->video.renderer->writePalette(ds->video.renderer, (address & (DS9_SIZE_PALETTE_RAM - 4)) + 2, value >> 16); + ds->video.renderer->writePalette(ds->video.renderer, address & (DS9_SIZE_PALETTE_RAM - 4), value)); break; case DS_REGION_VRAM: STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET); diff --git a/src/ds/renderers/software.c b/src/ds/renderers/software.c index 5baf94a84..627358341 100644 --- a/src/ds/renderers/software.c +++ b/src/ds/renderers/software.c @@ -5,10 +5,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include +#include + static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer); static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer); static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer); static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); +static void DSVideoSoftwareRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); static void DSVideoSoftwareRendererDrawScanline(struct DSVideoRenderer* renderer, int y); static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer); static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels); @@ -19,6 +23,7 @@ void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) { renderer->d.reset = DSVideoSoftwareRendererReset; renderer->d.deinit = DSVideoSoftwareRendererDeinit; renderer->d.writeVideoRegister = DSVideoSoftwareRendererWriteVideoRegister; + renderer->d.writePalette = DSVideoSoftwareRendererWritePalette; renderer->d.drawScanline = DSVideoSoftwareRendererDrawScanline; renderer->d.finishFrame = DSVideoSoftwareRendererFinishFrame; renderer->d.getPixels = DSVideoSoftwareRendererGetPixels; @@ -55,17 +60,155 @@ static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer) { } static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) { - mLOG(DS_VIDEO, STUB, "Stub video register write: %04X:%04X", address, value); + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + if (address <= DS9_REG_A_BLDY) { + value = softwareRenderer->engA.d.writeVideoRegister(&softwareRenderer->engA.d, address, value); + } else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) { + value = softwareRenderer->engB.d.writeVideoRegister(&softwareRenderer->engB.d, address & 0xFF, value); + } else { + mLOG(DS_VIDEO, STUB, "Stub video register write: %04X:%04X", address, value); + } + switch (address) { + case DS9_REG_A_DISPCNT_LO: + softwareRenderer->dispcntA &= 0xFFFF0000; + softwareRenderer->dispcntA |= value; + break; + case DS9_REG_A_DISPCNT_HI: + softwareRenderer->dispcntA &= 0x0000FFFF; + softwareRenderer->dispcntA |= value << 16; + break; + case DS9_REG_B_DISPCNT_LO: + softwareRenderer->dispcntB &= 0xFFFF0000; + softwareRenderer->dispcntB |= value; + break; + case DS9_REG_B_DISPCNT_HI: + softwareRenderer->dispcntB &= 0x0000FFFF; + softwareRenderer->dispcntB |= value << 16; + break; + } return value; } +static void DSVideoSoftwareRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + if (address < 0x200) { + softwareRenderer->engA.d.writePalette(&softwareRenderer->engA.d, address & 0x1FF, value); + } else { + softwareRenderer->engB.d.writePalette(&softwareRenderer->engB.d, address & 0x1FF, value); + } +} + +static void _drawScanlineA(struct DSVideoSoftwareRenderer* softwareRenderer, int y) { + memcpy(softwareRenderer->engA.d.vramBG, softwareRenderer->d.vramABG, sizeof(softwareRenderer->engA.d.vramBG)); + memcpy(softwareRenderer->engA.d.vramOBJ, softwareRenderer->d.vramAOBJ, sizeof(softwareRenderer->engA.d.vramOBJ)); + color_t* row = &softwareRenderer->engA.outputBuffer[softwareRenderer->outputBufferStride * y]; + + int x; + switch (DSRegisterDISPCNTGetDispMode(softwareRenderer->dispcntA)) { + case 0: + for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = GBA_COLOR_WHITE; + } + return; + case 1: + softwareRenderer->engA.d.drawScanline(&softwareRenderer->engA.d, y); + return; + case 2: { + uint16_t* vram = &softwareRenderer->d.vram[0x10000 * DSRegisterDISPCNTGetVRAMBlock(softwareRenderer->dispcntA)]; + for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) { + color_t color; + LOAD_16(color, (x + y * DS_VIDEO_HORIZONTAL_PIXELS) * 2, vram); +#ifndef COLOR_16_BIT + unsigned color32 = 0; + color32 |= (color << 9) & 0xF80000; + color32 |= (color << 3) & 0xF8; + color32 |= (color << 6) & 0xF800; + color32 |= (color32 >> 5) & 0x070707; + color = color32; +#elif COLOR_5_6_5 + uint16_t color16 = 0; + color16 |= (color & 0x001F) << 11; + color16 |= (color & 0x03E0) << 1; + color16 |= (color & 0x7C00) >> 10; + color = color16; +#endif + softwareRenderer->row[x] = color; + } + break; + } + case 3: + break; + } + +#ifdef COLOR_16_BIT +#if defined(__ARM_NEON) && !defined(__APPLE__) + _to16Bit(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS); +#else + for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = softwareRenderer->row[x]; + } +#endif +#else + memcpy(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS * sizeof(*row)); +#endif +} + +static void _drawScanlineB(struct DSVideoSoftwareRenderer* softwareRenderer, int y) { + memcpy(softwareRenderer->engB.d.vramBG, softwareRenderer->d.vramBBG, sizeof(softwareRenderer->engB.d.vramBG)); + memcpy(softwareRenderer->engB.d.vramOBJ, softwareRenderer->d.vramBOBJ, sizeof(softwareRenderer->engB.d.vramOBJ)); + color_t* row = &softwareRenderer->engB.outputBuffer[softwareRenderer->outputBufferStride * y]; + + int x; + switch (DSRegisterDISPCNTGetDispMode(softwareRenderer->dispcntB)) { + case 0: + for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = GBA_COLOR_WHITE; + } + return; + case 1: + softwareRenderer->engB.d.drawScanline(&softwareRenderer->engB.d, y); + return; + } + +#ifdef COLOR_16_BIT +#if defined(__ARM_NEON) && !defined(__APPLE__) + _to16Bit(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS); +#else + for (x = 0; x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = softwareRenderer->row[x]; + } +#endif +#else + memcpy(row, softwareRenderer->row, DS_VIDEO_HORIZONTAL_PIXELS * sizeof(*row)); +#endif +} + static void DSVideoSoftwareRendererDrawScanline(struct DSVideoRenderer* renderer, int y) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + softwareRenderer->engA.outputBuffer = softwareRenderer->outputBuffer; + softwareRenderer->engB.outputBuffer = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * DS_VIDEO_VERTICAL_PIXELS]; + softwareRenderer->engA.outputBufferStride = softwareRenderer->outputBufferStride; + softwareRenderer->engB.outputBufferStride = softwareRenderer->outputBufferStride; + + + _drawScanlineA(softwareRenderer, y); + _drawScanlineB(softwareRenderer, y); } static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; + softwareRenderer->engA.d.finishFrame(&softwareRenderer->engA.d); + softwareRenderer->engB.d.finishFrame(&softwareRenderer->engB.d); } static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels) { + struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer; +#ifdef COLOR_16_BIT +#error Not yet supported +#else + *stride = softwareRenderer->outputBufferStride; + *pixels = softwareRenderer->outputBuffer; +#endif } static void DSVideoSoftwareRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels) { diff --git a/src/ds/video.c b/src/ds/video.c index 9a5cd38f9..f587121c8 100644 --- a/src/ds/video.c +++ b/src/ds/video.c @@ -18,6 +18,7 @@ static void DSVideoDummyRendererInit(struct DSVideoRenderer* renderer); static void DSVideoDummyRendererReset(struct DSVideoRenderer* renderer); static void DSVideoDummyRendererDeinit(struct DSVideoRenderer* renderer); static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); +static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value); static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y); static void DSVideoDummyRendererFinishFrame(struct DSVideoRenderer* renderer); static void DSVideoDummyRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels); @@ -102,6 +103,7 @@ static struct DSVideoRenderer dummyRenderer = { .reset = DSVideoDummyRendererReset, .deinit = DSVideoDummyRendererDeinit, .writeVideoRegister = DSVideoDummyRendererWriteVideoRegister, + .writePalette = DSVideoDummyRendererWritePalette, .drawScanline = DSVideoDummyRendererDrawScanline, .finishFrame = DSVideoDummyRendererFinishFrame, .getPixels = DSVideoDummyRendererGetPixels, @@ -160,6 +162,10 @@ void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* ren video->renderer = renderer; renderer->palette = video->palette; renderer->vram = video->vram; + memcpy(renderer->vramABG, video->vramABG, sizeof(renderer->vramABG)); + memcpy(renderer->vramAOBJ, video->vramAOBJ, sizeof(renderer->vramAOBJ)); + memcpy(renderer->vramBBG, video->vramBBG, sizeof(renderer->vramBBG)); + memcpy(renderer->vramBOBJ, video->vramBOBJ, sizeof(renderer->vramBOBJ)); renderer->oam = &video->oam; video->renderer->init(video->renderer); } @@ -292,7 +298,8 @@ void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) { // TODO: Does a VCounter IRQ trigger on write? } -void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value) { +void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value) { + struct DSMemory* memory = &ds->memory; struct DSVRAMBankInfo info = _vramInfo[index][value & 0x7]; memset(&memory->vramMirror[index], 0, sizeof(memory->vramMirror[index])); memset(&memory->vramMode[index], 0, sizeof(memory->vramMode[index])); @@ -308,6 +315,32 @@ void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value) { memory->vramMirror[index][i + j] = 1 << index; } } + switch (info.mode) { + case 0: + for (i = 0; i < size; ++i) { + ds->video.vramABG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]; + ds->video.renderer->vramABG[offset + i] = ds->video.vramABG[offset + i]; + } + break; + case 1: + for (i = 0; i < size; ++i) { + ds->video.vramBBG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]; + ds->video.renderer->vramBBG[offset + i] = ds->video.vramBBG[offset + i]; + } + break; + case 2: + for (i = 0; i < size; ++i) { + ds->video.vramAOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]; + ds->video.renderer->vramAOBJ[offset + i] = ds->video.vramAOBJ[offset + i]; + } + break; + case 3: + for (i = 0; i < size; ++i) { + ds->video.vramBOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]; + ds->video.renderer->vramBOBJ[offset + i] = ds->video.vramBOBJ[offset + i]; + } + break; + } } static void DSVideoDummyRendererInit(struct DSVideoRenderer* renderer) { @@ -330,6 +363,12 @@ static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* r return value; } +static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) { + UNUSED(value); + UNUSED(address); + UNUSED(value); +} + static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y) { UNUSED(renderer); UNUSED(y); diff --git a/src/platform/test/perf-main.c b/src/platform/test/perf-main.c index 03fe093ce..cab485b59 100644 --- a/src/platform/test/perf-main.c +++ b/src/platform/test/perf-main.c @@ -108,7 +108,7 @@ int main(int argc, char** argv) { free(perfOpts.savestate); } - _outputBuffer = malloc(256 * 256 * 4); + _outputBuffer = malloc(256 * 384 * 4); if (perfOpts.csv) { puts("game_code,frames,duration,renderer"); }