From 0a46e11efe144d9b564e78521054fa5b48c352be Mon Sep 17 00:00:00 2001 From: TomW Date: Thu, 11 Feb 2016 20:35:49 +0000 Subject: [PATCH] Move ViRGE 2D blitter to seperate thread. --- src/vid_s3_virge.c | 462 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 452 insertions(+), 10 deletions(-) diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c index 949faf0..9ca98af 100644 --- a/src/vid_s3_virge.c +++ b/src/vid_s3_virge.c @@ -31,6 +31,31 @@ static int dither[4][4] = #define RB_FULL (RB_ENTRIES == RB_SIZE) #define RB_EMPTY (!RB_ENTRIES) +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + typedef struct s3d_t { uint32_t cmd_set; @@ -190,8 +215,22 @@ typedef struct virge_t int pri_x, pri_y, pri_w, pri_h; int sec_x, sec_y, sec_w, sec_h; } streams; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int virge_busy; } virge_t; +static inline void wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + static void queue_triangle(virge_t *virge); static void s3_virge_recalctimings(svga_t *svga); @@ -668,6 +707,14 @@ static void s3_virge_updatemapping(virge_t *virge) } +static void s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) { @@ -778,55 +825,72 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) break; case 0x8504: - if (virge->s3d_busy) + if (virge->s3d_busy || virge->virge_busy) ret = (0x10 << 8); else ret = (0x10 << 8) | (1 << 13); + if (!virge->virge_busy) + wake_fifo_thread(virge); // pclog("Read status %04x %i\n", ret, virge->s3d_busy); break; case 0xa4d4: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_base; break; case 0xa4d8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.dest_base; break; case 0xa4dc: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; break; case 0xa4e0: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; break; case 0xa4e4: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; break; case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.mono_pat_0; break; case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.mono_pat_1; break; case 0xa4f0: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.pat_bg_clr; break; case 0xa4f4: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.pat_fg_clr; break; case 0xa4f8: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_bg_clr; break; case 0xa4fc: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.src_fg_clr; break; case 0xa500: + s3_virge_wait_fifo_idle(virge); ret = virge->s3d.cmd_set; break; case 0xa504: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; break; case 0xa508: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; break; case 0xa50c: + s3_virge_wait_fifo_idle(virge); ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; break; @@ -836,6 +900,380 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) // /*if ((addr & 0xfffc) != 0x8504) */pclog("%02x\n", ret); return ret; } + +static void fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) + { + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = (fifo->addr_type & FIFO_ADDR) & 4; + int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; + y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; + y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + } +} + +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); +} + static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; @@ -844,7 +1282,9 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) // pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc); reg_writes++; if ((addr & 0xfffc) < 0x8000) - s3_virge_bitblt(virge, 8, val); + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); + } else switch (addr & 0xffff) { case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: @@ -872,10 +1312,7 @@ static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) // pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc); if ((addr & 0xfffc) < 0x8000) { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); - else - s3_virge_bitblt(virge, 16, val); + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); } else switch (addr & 0xfffe) { @@ -895,10 +1332,11 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) if ((addr & 0xfffc) < 0x8000) { - if (virge->s3d.cmd_set & CMD_SET_MS) - s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); - else - s3_virge_bitblt(virge, 32, val); + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + else if ((addr & 0xe000) == 0xa000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); } else switch (addr & 0xfffc) { @@ -3468,6 +3906,10 @@ static void *s3_virge_375_init() virge->wake_main_thread = thread_create_event(); virge->not_full_event = thread_create_event(); virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); return virge; }