diff --git a/output/dll/pizza.wbx.gz b/output/dll/pizza.wbx.gz index 5937922ea3..cbc7062d17 100644 Binary files a/output/dll/pizza.wbx.gz and b/output/dll/pizza.wbx.gz differ diff --git a/waterbox/pizza/lib/sgb.c b/waterbox/pizza/lib/sgb.c index a006431c78..fbb71b6e5f 100644 --- a/waterbox/pizza/lib/sgb.c +++ b/waterbox/pizza/lib/sgb.c @@ -75,7 +75,7 @@ typedef struct // frame data uint8_t frame[160 * 144]; // the most recent obtained full frame - uint8_t frozenframe[160 * 144]; // the most recent saved full frame (MASK_EN) + uint32_t frozenframe[256 * 224]; // the most recent saved full frame (MASK_EN) uint8_t attr[20 * 18]; // current attr map for the GB screen uint8_t auxattr[45][20 * 18]; // 45 attr files @@ -433,7 +433,8 @@ static void cmd_mask(void) case 2: case 3: sgb.active_mask = 1; - memset(sgb.frozenframe, 0, sizeof(sgb.frozenframe)); + for (int i = 0; i < 256 * 224; i++) + sgb.frozenframe[i] = sgb.palette[0][0]; break; } } @@ -862,32 +863,10 @@ static void do_vram_transfer(void) } } -// 160x144 32bpp pixel data -// assumed to contain exact pixel values 00, 55, aa, ff -void sgb_take_frame(uint32_t *vbuff) -{ - for (int i = 0; i < 160 * 144; i++) - { - sgb.frame[i] = 3 - (vbuff[i] >> 6 & 3); // 0, 1, 2, or 3 for each pixel - } - if (sgb.waiting_transfer != TRN_NONE) - { - if (!--sgb.transfer_countdown) - { - do_vram_transfer(); - sgb.waiting_transfer = TRN_NONE; - } - } - if (!sgb.active_mask) - { - memcpy(sgb.frozenframe, sgb.frame, sizeof(sgb.frame)); - } -} - static void sgb_render_frame_gb(uint32_t *vbuff) { const uint8_t *attr = sgb.attr; - const uint8_t *src = sgb.active_mask ? sgb.frozenframe : sgb.frame; + const uint8_t *src = sgb.frame; uint32_t *dst = vbuff + ((224 - 144) / 2 * 256 + (256 - 160) / 2); for (int j = 0; j < 144; j++) @@ -951,12 +930,35 @@ static void sgb_render_border(uint32_t *vbuff) } } +// 160x144 32bpp pixel data +// assumed to contain exact pixel values 00, 55, aa, ff +void sgb_take_frame(uint32_t *vbuff) +{ + for (int i = 0; i < 160 * 144; i++) + { + sgb.frame[i] = 3 - (vbuff[i] >> 6 & 3); // 0, 1, 2, or 3 for each pixel + } + if (sgb.waiting_transfer != TRN_NONE) + { + if (!--sgb.transfer_countdown) + { + do_vram_transfer(); + sgb.waiting_transfer = TRN_NONE; + } + } + if (!sgb.active_mask) + { + // render the frame now + for (int i = 0; i < 256 * 224; i++) + sgb.frozenframe[i] = sgb.palette[0][0]; + sgb_render_frame_gb(sgb.frozenframe); + sgb_render_border(sgb.frozenframe); + } +} + void sgb_render_frame(uint32_t *vbuff) { - for (int i = 0; i < 256 * 224; i++) - vbuff[i] = sgb.palette[0][0]; - sgb_render_frame_gb(vbuff); - sgb_render_border(vbuff); + memcpy(vbuff, sgb.frozenframe, sizeof(sgb.frozenframe)); } void sgb_render_audio(uint64_t time, void (*callback)(int16_t l, int16_t r, uint64_t time)) diff --git a/waterbox/pizza/lib/sgb.h b/waterbox/pizza/lib/sgb.h index 4c1009ac08..35e76dcad9 100644 --- a/waterbox/pizza/lib/sgb.h +++ b/waterbox/pizza/lib/sgb.h @@ -1,16 +1,36 @@ #pragma once #include +// whenever a time is asked for, it is relative to a clock that ticks 35112 times +// per nominal frame on the GB lcd, starts at 0 when emulation begins, and never resets/rebases + +// write to MMIO ff00. only bits 4 and 5 are used void sgb_write_ff00(uint8_t val, uint64_t time); +// read from MMIO ff00. supplies data for all 8 bits uint8_t sgb_read_ff00(uint64_t time); +// set controller data to be used by subsequent controller reads +// buttons[0] = controller 1, buttons[3] = controller 4 +// 7......0 +// DULRSsBA void sgb_set_controller_data(const uint8_t* buttons); +// initialize the SGB module. pass an SPC file that results from the real S-CPU initialization, +// and the length of that file int sgb_init(const uint8_t* spc, int length); +// call whenever the gameboy has finished producing a video frame +// data is 32bpp 160x144 screen data. for each pixel: +//31 7 0 +// xxxxxxxx xxxxxxxx xxxxxxxx DDxxxxxx -- DD = 0, 1, 2, or 3. x = don't care void sgb_take_frame(uint32_t* vbuff); +// copy the finished video frame to an output buffer. pixel format is 32bpp xrgb +// can be called at any time, including right after sgb_take_frame void sgb_render_frame(uint32_t* vbuff); +// call to finish a frame's worth of audio. should be called once every 35112 time units (some jitter is OK) +// callback will be called with L and R sample values for various time points +// between the last time sgb_render_audio was called and now void sgb_render_audio(uint64_t time, void(*callback)(int16_t l, int16_t r, uint64_t time));