186 lines
6.2 KiB
C
186 lines
6.2 KiB
C
#include "video-software.h"
|
|
|
|
#include "gba.h"
|
|
#include "gba-io.h"
|
|
|
|
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
|
|
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
|
|
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
|
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
|
|
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer);
|
|
|
|
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer);
|
|
static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareBackground* bg, uint16_t value);
|
|
|
|
void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
|
|
renderer->d.init = GBAVideoSoftwareRendererInit;
|
|
renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
|
|
renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
|
|
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
|
|
renderer->d.finishFrame = GBAVideoSoftwareRendererFinishFrame;
|
|
|
|
{
|
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
renderer->mutex = mutex;
|
|
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
|
renderer->cond = cond;
|
|
}
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {
|
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
|
int i;
|
|
|
|
softwareRenderer->dispcnt.packed = 0x0080;
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
struct GBAVideoSoftwareBackground* bg = &softwareRenderer->bg[i];
|
|
bg->index = i;
|
|
bg->enabled = 0;
|
|
bg->priority = 0;
|
|
bg->charBase = 0;
|
|
bg->mosaic = 0;
|
|
bg->multipalette = 0;
|
|
bg->screenBase = 0;
|
|
bg->overflow = 0;
|
|
bg->size = 0;
|
|
bg->x = 0;
|
|
bg->y = 0;
|
|
bg->refx = 0;
|
|
bg->refy = 0;
|
|
bg->dx = 256;
|
|
bg->dmx = 0;
|
|
bg->dy = 0;
|
|
bg->dmy = 256;
|
|
bg->sx = 0;
|
|
bg->sy = 0;
|
|
}
|
|
|
|
pthread_mutex_init(&softwareRenderer->mutex, 0);
|
|
pthread_cond_init(&softwareRenderer->cond, 0);
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer) {
|
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
|
|
|
pthread_mutex_destroy(&softwareRenderer->mutex);
|
|
pthread_cond_destroy(&softwareRenderer->cond);
|
|
}
|
|
|
|
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
|
switch (address) {
|
|
case REG_DISPCNT:
|
|
value &= 0xFFFB;
|
|
softwareRenderer->dispcnt.packed = value;
|
|
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
|
|
break;
|
|
case REG_BG0CNT:
|
|
value &= 0xFFCF;
|
|
GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[0], value);
|
|
break;
|
|
case REG_BG1CNT:
|
|
value &= 0xFFCF;
|
|
GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[1], value);
|
|
break;
|
|
case REG_BG2CNT:
|
|
value &= 0xFFCF;
|
|
GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[2], value);
|
|
break;
|
|
case REG_BG3CNT:
|
|
value &= 0xFFCF;
|
|
GBAVideoSoftwareRendererWriteBGCNT(&softwareRenderer->bg[3], value);
|
|
break;
|
|
case REG_BG0HOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[0].x = value;
|
|
break;
|
|
case REG_BG0VOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[0].y = value;
|
|
break;
|
|
case REG_BG1HOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[1].x = value;
|
|
break;
|
|
case REG_BG1VOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[1].y = value;
|
|
break;
|
|
case REG_BG2HOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[2].x = value;
|
|
break;
|
|
case REG_BG2VOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[2].y = value;
|
|
break;
|
|
case REG_BG3HOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[3].x = value;
|
|
break;
|
|
case REG_BG3VOFS:
|
|
value &= 0x01FF;
|
|
softwareRenderer->bg[3].y = value;
|
|
break;
|
|
default:
|
|
GBALog(GBA_LOG_STUB, "Stub video register write: %03x", address);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
|
int x;
|
|
uint16_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
|
if (softwareRenderer->dispcnt.forcedBlank) {
|
|
for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
|
|
row[x] = 0x7FFF;
|
|
}
|
|
return;
|
|
}
|
|
for (x = 0; x < 16; ++x) {
|
|
row[(x * 15) + 0] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 1] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 2] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 3] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 4] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 5] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 6] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 7] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 8] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 9] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 10] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 11] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 12] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 13] = renderer->palette[x + (y / 5) * 16];
|
|
row[(x * 15) + 14] = renderer->palette[x + (y / 5) * 16];
|
|
}
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {
|
|
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
|
|
|
pthread_mutex_lock(&softwareRenderer->mutex);
|
|
pthread_cond_wait(&softwareRenderer->cond, &softwareRenderer->mutex);
|
|
pthread_mutex_unlock(&softwareRenderer->mutex);
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer) {
|
|
renderer->bg[0].enabled = renderer->dispcnt.bg0Enable;
|
|
renderer->bg[1].enabled = renderer->dispcnt.bg1Enable;
|
|
renderer->bg[2].enabled = renderer->dispcnt.bg2Enable;
|
|
renderer->bg[3].enabled = renderer->dispcnt.bg3Enable;
|
|
}
|
|
|
|
static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareBackground* bg, uint16_t value) {
|
|
union GBARegisterBGCNT reg = { .packed = value };
|
|
bg->priority = reg.priority;
|
|
bg->charBase = reg.charBase << 13;
|
|
bg->mosaic = reg.mosaic;
|
|
bg->multipalette = reg.multipalette;
|
|
bg->screenBase = reg.screenBase << 10;
|
|
bg->overflow = reg.overflow;
|
|
bg->size = reg.size;
|
|
}
|