Move ViRGE 2D blitter to seperate thread.

This commit is contained in:
TomW 2016-02-11 20:35:49 +00:00
commit 0a46e11efe

View file

@ -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;
}