Split Voodoo render thread into FIFO thread and one or two render threads.

This commit is contained in:
TomW 2015-08-19 19:21:51 +01:00
commit 726e3bfcd9

View file

@ -21,6 +21,8 @@ static int tris = 0;
static uint64_t status_time = 0;
static uint64_t voodoo_time = 0;
static int voodoo_render_time[2] = {0, 0};
static int voodoo_render_time_old[2] = {0, 0};
typedef union int_float
{
@ -66,6 +68,17 @@ enum
FIFO_WRITEL_TEX = (0x04 << 24)
};
#define PARAM_SIZE 1024
#define PARAM_MASK (PARAM_SIZE - 1)
#define PARAM_ENTRY_SIZE (1 << 31)
#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0])
#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1])
#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE)
#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE)
#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx)
#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx)
typedef struct
{
uint32_t addr_type;
@ -135,6 +148,8 @@ typedef struct voodoo_params_t
uint32_t front_offset;
uint32_t swapbufferCMD;
rgba_u palette[256];
} voodoo_params_t;
typedef struct voodoo_t
@ -207,14 +222,22 @@ typedef struct voodoo_t
rgba_u ncc_lookup[2][256];
int ncc_dirty;
thread_t *render_thread;
event_t *wake_render_thread;
thread_t *fifo_thread;
thread_t *render_thread[2];
event_t *wake_fifo_thread;
event_t *wake_main_thread;
event_t *not_full_event;
event_t *fifo_not_full_event;
event_t *render_not_full_event[2];
event_t *wake_render_thread[2];
int voodoo_busy;
int render_voodoo_busy[2];
int pixel_count, tri_count, frame_count;
int render_threads;
int odd_even_mask;
int pixel_count[2], tri_count, frame_count;
int pixel_count_old[2];
int wr_count, rd_count, tex_count;
int retrace_count;
@ -233,6 +256,9 @@ typedef struct voodoo_t
fifo_entry_t fifo[FIFO_SIZE];
int fifo_read_idx, fifo_write_idx;
int cmd_read, cmd_written;
voodoo_params_t params_buffer[PARAM_SIZE];
volatile int params_read_idx[2], params_write_idx;
int flush;
@ -891,6 +917,8 @@ typedef struct voodoo_state_t
int tex_r, tex_g, tex_b, tex_a;
int tex_s, tex_t;
int clamp_s, clamp_t;
int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy;
uint8_t *tex[LOD_MAX+1];
uint16_t *tex_w[LOD_MAX+1];
@ -1599,7 +1627,7 @@ static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params,
#define dither ( params->fbzMode & FBZ_DITHER)
#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2)
static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend)
static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even)
{
/* int rgb_sel = params->fbzColorPath & 3;
int a_sel = (params->fbzColorPath >> 2) & 3;
@ -1688,12 +1716,20 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood
int64_t w = state->base_w;
uint16_t *fb_mem, *aux_mem;
x = (params->vertexAx << 12) + ((state->dxAC * (real_y - params->vertexAy)) >> 4);
x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4);
if (real_y < params->vertexBy)
x2 = (params->vertexAx << 12) + ((state->dxAB * (real_y - params->vertexAy)) >> 4);
if (real_y < state->vertexBy)
x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4);
else
x2 = (params->vertexBx << 12) + ((state->dxBC * (real_y - params->vertexBy)) >> 4);
x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4);
if (params->fbzMode & (1 << 17))
real_y = voodoo->v_disp - (real_y >> 4);
else
real_y >>= 4;
if ((real_y & voodoo->odd_even_mask) != odd_even)
goto next_line;
start_x = x;
@ -1701,13 +1737,13 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood
x2 -= (1 << 16);
else
x -= (1 << 16);
dx = ((x + 0x7000) >> 16) - (((params->vertexAx << 12) + 0x7000) >> 16);
dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16);
start_x2 = x + 0x7000;
x = (x + 0x7000) >> 16;
x2 = (x2 + 0x7000) >> 16;
if (voodoo_output)
pclog("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, params->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, tmu0_t);
pclog("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, tmu0_t);
ir += (params->dRdX * dx);
ig += (params->dGdX * dx);
@ -1722,11 +1758,6 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood
if (voodoo_output)
pclog("%08llx %lli %lli\n", tmu0_t, tmu0_t >> (18+state->lod), (tmu0_t + (1 << 17+state->lod)) >> (18+state->lod));
if (params->fbzMode & (1 << 17))
real_y = voodoo->v_disp - (real_y >> 4);
else
real_y >>= 4;
if (params->fbzMode & 1)
{
if (state->xdir > 0)
@ -1787,7 +1818,7 @@ static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, vood
do
{
start_x = x;
voodoo->pixel_count++;
voodoo->pixel_count[odd_even]++;
if (voodoo_output)
pclog(" X=%03i T=%08x\n", x, tmu0_t);
// if (voodoo->fbzMode & FBZ_RGB_WMASK)
@ -2179,7 +2210,7 @@ next_line:
}
}
static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params)
static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even)
{
voodoo_state_t state;
int vertexAy_adjusted;
@ -2201,75 +2232,9 @@ static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params)
if ((params->vertexAy & 0xf) > 8)
dy += 16;
/* pclog("voodoo_triangle %i : vA %f, %f vB %f, %f vC %f, %f f %i\n", tris, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0,
/* pclog("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0,
(float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0,
(float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, params->tformat);*/
if (params->fbzColorPath & FBZ_PARAM_ADJUST)
{
params->startR += (dx*params->dRdX + dy*params->dRdY) >> 4;
params->startG += (dx*params->dGdX + dy*params->dGdY) >> 4;
params->startB += (dx*params->dBdX + dy*params->dBdY) >> 4;
params->startA += (dx*params->dAdX + dy*params->dAdY) >> 4;
params->startZ += (dx*params->dZdX + dy*params->dZdY) >> 4;
params->tmu[0].startS += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4;
params->tmu[0].startT += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4;
params->tmu[0].startW += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4;
params->startW += (dx*params->dWdX + dy*params->dWdY) >> 4;
}
tris++;
if (params->vertexAy & 0x8000)
params->vertexAy |= 0xffff0000;
else
params->vertexAy &= ~0xffff0000;
if (params->vertexBy & 0x8000)
params->vertexBy |= 0xffff0000;
else
params->vertexBy &= ~0xffff0000;
if (params->vertexCy & 0x8000)
params->vertexCy |= 0xffff0000;
else
params->vertexCy &= ~0xffff0000;
params->vertexAx = params->vertexAx & ~0xffff0000;
if (params->vertexAx & 0x8000)
params->vertexAx |= 0xffff0000;
params->vertexBx = params->vertexBx & ~0xffff0000;
if (params->vertexBx & 0x8000)
params->vertexBx |= 0xffff0000;
params->vertexCx = params->vertexCx & ~0xffff0000;
if (params->vertexCx & 0x8000)
params->vertexCx |= 0xffff0000;
vertexAy_adjusted = (params->vertexAy+7) >> 4;
vertexBy_adjusted = (params->vertexBy+7) >> 4;
vertexCy_adjusted = (params->vertexCy+7) >> 4;
if (params->vertexBy - params->vertexAy)
state.dxAB = (int)((((int64_t)params->vertexBx << 12) - ((int64_t)params->vertexAx << 12)) << 4) / (int)(params->vertexBy - params->vertexAy);
else
state.dxAB = 0;
if (params->vertexCy - params->vertexAy)
state.dxAC = (int)((((int64_t)params->vertexCx << 12) - ((int64_t)params->vertexAx << 12)) << 4) / (int)(params->vertexCy - params->vertexAy);
else
state.dxAC = 0;
if (params->vertexCy - params->vertexBy)
state.dxBC = (int)((((int64_t)params->vertexCx << 12) - ((int64_t)params->vertexBx << 12)) << 4) / (int)(params->vertexCy - params->vertexBy);
else
state.dxBC = 0;
state.lod_min = (params->tLOD & 0x3f) << 6;
state.lod_max = ((params->tLOD >> 6) & 0x3f) << 6;
if (state.lod_max > 0x800)
state.lod_max = 0x800;
state.xstart = state.xend = params->vertexAx << 8;
state.xdir = params->sign ? -1 : 1;
state.y = (params->vertexAy + 8) >> 4;
state.ydir = 1;
state.base_r = params->startR;
state.base_g = params->startG;
state.base_b = params->startB;
@ -2280,6 +2245,68 @@ static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params)
state.tmu[0].base_w = params->tmu[0].startW;
state.base_w = params->startW;
if (params->fbzColorPath & FBZ_PARAM_ADJUST)
{
state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4;
state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4;
state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4;
state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4;
state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4;
state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4;
state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4;
state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4;
state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4;
}
tris++;
state.vertexAy = params->vertexAy & ~0xffff0000;
if (state.vertexAy & 0x8000)
state.vertexAy |= 0xffff0000;
state.vertexBy = params->vertexBy & ~0xffff0000;
if (state.vertexBy & 0x8000)
state.vertexBy |= 0xffff0000;
state.vertexCy = params->vertexCy & ~0xffff0000;
if (state.vertexCy & 0x8000)
state.vertexCy |= 0xffff0000;
state.vertexAx = params->vertexAx & ~0xffff0000;
if (state.vertexAx & 0x8000)
state.vertexAx |= 0xffff0000;
state.vertexBx = params->vertexBx & ~0xffff0000;
if (state.vertexBx & 0x8000)
state.vertexBx |= 0xffff0000;
state.vertexCx = params->vertexCx & ~0xffff0000;
if (state.vertexCx & 0x8000)
state.vertexCx |= 0xffff0000;
vertexAy_adjusted = (state.vertexAy+7) >> 4;
vertexBy_adjusted = (state.vertexBy+7) >> 4;
vertexCy_adjusted = (state.vertexCy+7) >> 4;
if (state.vertexBy - state.vertexAy)
state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy);
else
state.dxAB = 0;
if (state.vertexCy - state.vertexAy)
state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy);
else
state.dxAC = 0;
if (state.vertexCy - state.vertexBy)
state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy);
else
state.dxBC = 0;
state.lod_min = (params->tLOD & 0x3f) << 6;
state.lod_max = ((params->tLOD >> 6) & 0x3f) << 6;
if (state.lod_max > 0x800)
state.lod_max = 0x800;
state.xstart = state.xend = state.vertexAx << 8;
state.xdir = params->sign ? -1 : 1;
state.y = (state.vertexAy + 8) >> 4;
state.ydir = 1;
tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14);
tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14);
@ -2296,17 +2323,107 @@ static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params)
lodbias |= ~0x3f;
state.tmu[0].lod = LOD + (lodbias << 6);
state.palette = params->palette;
voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even);
}
static inline void wake_render_thread(voodoo_t *voodoo)
{
thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/
if (voodoo->render_threads == 2)
thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/
}
static inline void wait_for_render_thread_idle(voodoo_t *voodoo)
{
while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1]))
{
wake_render_thread(voodoo);
if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0])
thread_wait_event(voodoo->render_not_full_event[0], 1);
if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1]))
thread_wait_event(voodoo->render_not_full_event[1], 1);
}
}
static void render_thread(void *param, int odd_even)
{
voodoo_t *voodoo = (voodoo_t *)param;
while (1)
{
thread_set_event(voodoo->render_not_full_event[odd_even]);
thread_wait_event(voodoo->wake_render_thread[odd_even], -1);
thread_reset_event(voodoo->wake_render_thread[odd_even]);
voodoo->render_voodoo_busy[odd_even] = 1;
while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1))
{
uint64_t start_time = timer_read();
uint64_t end_time;
voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK];
voodoo_triangle(voodoo, params, odd_even);
voodoo->params_read_idx[odd_even]++;
if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10))
thread_set_event(voodoo->render_not_full_event[odd_even]);
end_time = timer_read();
voodoo_render_time[odd_even] += end_time - start_time;
}
voodoo->render_voodoo_busy[odd_even] = 0;
}
}
static void render_thread_1(void *param)
{
render_thread(param, 0);
}
static void render_thread_2(void *param)
{
render_thread(param, 1);
}
static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params)
{
voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK];
while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2))
{
thread_reset_event(voodoo->render_not_full_event[0]);
if (voodoo->render_threads == 2)
thread_reset_event(voodoo->render_not_full_event[1]);
if (PARAM_FULL_1)
{
thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/
}
if (voodoo->render_threads == 2 && PARAM_FULL_2)
{
thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/
}
}
memcpy(params_new, params, sizeof(voodoo_params_t) - sizeof(voodoo->palette));
/*Copy palette data if required*/
switch (params->tformat)
{
case TEX_PAL8: case TEX_APAL88:
state.palette = voodoo->palette;
memcpy(params_new->palette, voodoo->palette, sizeof(voodoo->palette));
break;
case TEX_Y4I2Q2:
state.palette = voodoo->ncc_lookup[(params->textureMode & TEXTUREMODE_NCC_SEL) ? 1 : 0];
memcpy(params_new->palette, voodoo->ncc_lookup[(params->textureMode & TEXTUREMODE_NCC_SEL) ? 1 : 0], sizeof(voodoo->palette));
break;
}
voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted);
voodoo->params_write_idx++;
if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4))
wake_render_thread(voodoo);
}
static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params)
@ -2423,6 +2540,7 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
pclog("Swap buffer %08x %d %p\n", val, voodoo->swap_count, &voodoo->swap_count);
// voodoo->front_offset = params->front_offset;
wait_for_render_thread_idle(voodoo);
if (!(val & 1))
{
memset(voodoo->dirty_line, 1, 1024);
@ -2437,8 +2555,8 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
while (voodoo->swap_pending)
{
thread_wait_event(voodoo->wake_render_thread, -1);
thread_reset_event(voodoo->wake_render_thread);
thread_wait_event(voodoo->wake_fifo_thread, -1);
thread_reset_event(voodoo->wake_fifo_thread);
if (voodoo->swap_pending && voodoo->flush)
{
/*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/
@ -2569,7 +2687,7 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
voodoo_update_ncc(voodoo);
voodoo->ncc_dirty = 0;
voodoo_triangle(voodoo, &voodoo->params);
queue_triangle(voodoo, &voodoo->params);
voodoo->cmd_read++;
break;
@ -2730,7 +2848,7 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
voodoo_update_ncc(voodoo);
voodoo->ncc_dirty = 0;
voodoo_triangle(voodoo, &voodoo->params);
queue_triangle(voodoo, &voodoo->params);
voodoo->cmd_read++;
break;
@ -2768,6 +2886,7 @@ static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
voodoo->cmd_read++;
break;
case SST_fastfillCMD:
wait_for_render_thread_idle(voodoo);
voodoo_fastfill(voodoo, &voodoo->params);
voodoo->cmd_read++;
break;
@ -3350,9 +3469,9 @@ static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p)
*(uint32_t *)(&voodoo->tex_mem[addr & voodoo->texture_mask]) = val;
}
static inline void wake_render_thread(voodoo_t *voodoo)
static inline void wake_fifo_thread(voodoo_t *voodoo)
{
thread_set_event(voodoo->wake_render_thread); /*Wake up render thread if moving from idle*/
thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
}
static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val)
@ -3362,10 +3481,10 @@ static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t
if (FIFO_FULL)
{
thread_reset_event(voodoo->not_full_event);
thread_reset_event(voodoo->fifo_not_full_event);
if (FIFO_FULL)
{
thread_wait_event(voodoo->not_full_event, -1); /*Wait for room in ringbuffer*/
thread_wait_event(voodoo->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/
}
}
@ -3375,7 +3494,7 @@ static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t
voodoo->fifo_write_idx++;
if (FIFO_ENTRIES > 0xe000)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
}
static uint16_t voodoo_readw(uint32_t addr, void *p)
@ -3389,9 +3508,10 @@ static uint16_t voodoo_readw(uint32_t addr, void *p)
voodoo->flush = 1;
while (!FIFO_EMPTY)
{
wake_render_thread(voodoo);
thread_wait_event(voodoo->not_full_event, 1);
wake_fifo_thread(voodoo);
thread_wait_event(voodoo->fifo_not_full_event, 1);
}
wait_for_render_thread_idle(voodoo);
voodoo->flush = 0;
return voodoo_fb_readw(addr, voodoo);
@ -3416,9 +3536,10 @@ static uint32_t voodoo_readl(uint32_t addr, void *p)
voodoo->flush = 1;
while (!FIFO_EMPTY)
{
wake_render_thread(voodoo);
thread_wait_event(voodoo->not_full_event, 1);
wake_fifo_thread(voodoo);
thread_wait_event(voodoo->fifo_not_full_event, 1);
}
wait_for_render_thread_idle(voodoo);
voodoo->flush = 0;
temp = voodoo_fb_readl(addr, voodoo);
@ -3436,16 +3557,17 @@ static uint32_t voodoo_readl(uint32_t addr, void *p)
if (voodoo->cmd_written - voodoo->cmd_read)
temp |= 0x380; /*Busy*/
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_lfbMode:
voodoo->flush = 1;
while (!FIFO_EMPTY)
{
wake_render_thread(voodoo);
thread_wait_event(voodoo->not_full_event, 1);
wake_fifo_thread(voodoo);
thread_wait_event(voodoo->fifo_not_full_event, 1);
}
wait_for_render_thread_idle(voodoo);
voodoo->flush = 0;
temp = voodoo->lfbMode;
@ -3534,31 +3656,31 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
voodoo->swap_count++;
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_triangleCMD:
voodoo->cmd_written++;
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_ftriangleCMD:
voodoo->cmd_written++;
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_fastfillCMD:
voodoo->cmd_written++;
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_nopCMD:
voodoo->cmd_written++;
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
if (!voodoo->voodoo_busy)
wake_render_thread(voodoo);
wake_fifo_thread(voodoo);
break;
case SST_fbiInit4:
@ -3659,16 +3781,15 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
}
}
static void render_thread(void *param)
static void fifo_thread(void *param)
{
voodoo_t *voodoo = (voodoo_t *)param;
while (1)
{
thread_set_event(voodoo->not_full_event);
thread_wait_event(voodoo->wake_render_thread, -1);
thread_reset_event(voodoo->wake_render_thread);
thread_set_event(voodoo->fifo_not_full_event);
thread_wait_event(voodoo->wake_fifo_thread, -1);
thread_reset_event(voodoo->wake_fifo_thread);
voodoo->voodoo_busy = 1;
while (!FIFO_EMPTY)
{
@ -3682,13 +3803,19 @@ static void render_thread(void *param)
voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
break;
case FIFO_WRITEW_FB:
wait_for_render_thread_idle(voodoo);
voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
break;
case FIFO_WRITEL_FB:
wait_for_render_thread_idle(voodoo);
voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
break;
case FIFO_WRITEL_TEX:
voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
if (!(fifo->addr_type & 0x600000))
{
wait_for_render_thread_idle(voodoo);
voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
}
break;
}
@ -3696,7 +3823,7 @@ static void render_thread(void *param)
fifo->addr_type = FIFO_INVALID;
if (FIFO_ENTRIES > 0xe000)
thread_set_event(voodoo->not_full_event);
thread_set_event(voodoo->fifo_not_full_event);
end_time = timer_read();
voodoo_time += end_time - start_time;
@ -3953,13 +4080,12 @@ void voodoo_callback(void *p)
voodoo->retrace_count++;
if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval))
{
// pclog("Retrace swap %i %p\n", voodoo->swap_count, &voodoo->swap_count);
memset(voodoo->dirty_line, 1, 1024);
voodoo->retrace_count = 0;
voodoo->front_offset = voodoo->swap_offset;
voodoo->swap_count--;
voodoo->swap_pending = 0;
thread_set_event(voodoo->wake_render_thread);
thread_set_event(voodoo->wake_fifo_thread);
voodoo->frame_count++;
}
}
@ -3993,6 +4119,8 @@ static void voodoo_add_status_info(char *s, int max_len, void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
char temps[256];
int pixel_count_current[2];
int pixel_count_total;
uint64_t new_time = timer_read();
uint64_t status_diff = new_time - status_time;
status_time = new_time;
@ -4001,12 +4129,21 @@ static void voodoo_add_status_info(char *s, int max_len, void *p)
status_diff = 1;
svga_add_status_info(s, max_len, &voodoo->svga);
sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec\n%d reads/sec\n%d write/sec\n%d tex/sec\n", (double)voodoo->pixel_count/1000000.0, (double)voodoo->tri_count/1000.0, ((double)voodoo_time * 100.0) / timer_freq, ((double)voodoo_time * 100.0) / status_diff, voodoo->frame_count, voodoo->rd_count, voodoo->wr_count, voodoo->tex_count);
pixel_count_current[0] = voodoo->pixel_count[0];
pixel_count_current[1] = voodoo->pixel_count[1];
pixel_count_total = (pixel_count_current[0] + pixel_count_current[1]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1]);
sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec\n%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n"/*%d reads/sec\n%d write/sec\n%d tex/sec\n*/, (double)pixel_count_total/1000000.0, (double)voodoo->tri_count/1000.0, ((double)voodoo_time * 100.0) / timer_freq, ((double)voodoo_time * 100.0) / status_diff, voodoo->frame_count,
((double)voodoo_render_time[0] * 100.0) / timer_freq, ((double)voodoo_render_time[0] * 100.0) / status_diff,
((double)voodoo_render_time[1] * 100.0) / timer_freq, ((double)voodoo_render_time[1] * 100.0) / status_diff);
strncat(s, temps, max_len);
voodoo->pixel_count = voodoo->tri_count = voodoo->frame_count = 0;
voodoo->pixel_count_old[0] = pixel_count_current[0];
voodoo->pixel_count_old[1] = pixel_count_current[1];
voodoo->tri_count = voodoo->frame_count = 0;
voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0;
voodoo_time = 0;
voodoo_render_time[0] = voodoo_render_time[1] = 0;
}
static void voodoo_speed_changed(void *p)
@ -4028,6 +4165,8 @@ void *voodoo_init()
voodoo->texture_mask = (voodoo->texture_size << 20) - 1;
voodoo->fb_size = device_get_config_int("framebuffer_memory");
voodoo->fb_mask = (voodoo->fb_size << 20) - 1;
voodoo->render_threads = device_get_config_int("render_threads");
voodoo->odd_even_mask = voodoo->render_threads - 1;
voodoo_generate_filter(voodoo); /*generate filter lookup tables*/
@ -4044,10 +4183,17 @@ void *voodoo_init()
voodoo->svga = svga_get_pri();
voodoo->fbiInit0 = 0;
voodoo->wake_render_thread = thread_create_event();
voodoo->wake_fifo_thread = thread_create_event();
voodoo->wake_render_thread[0] = thread_create_event();
voodoo->wake_render_thread[1] = thread_create_event();
voodoo->wake_main_thread = thread_create_event();
voodoo->not_full_event = thread_create_event();
voodoo->render_thread = thread_create(render_thread, voodoo);
voodoo->fifo_not_full_event = thread_create_event();
voodoo->render_not_full_event[0] = thread_create_event();
voodoo->render_not_full_event[1] = thread_create_event();
voodoo->fifo_thread = thread_create(fifo_thread, voodoo);
voodoo->render_thread[0] = thread_create(render_thread_1, voodoo);
if (voodoo->render_threads == 2)
voodoo->render_thread[1] = thread_create(render_thread_2, voodoo);
for (c = 0; c < 0x100; c++)
{
@ -4101,10 +4247,17 @@ void voodoo_close(void *p)
fwrite(voodoo->tex_mem, 2048*1024, 1, f);
fclose(f);
thread_kill(voodoo->render_thread);
thread_destroy_event(voodoo->not_full_event);
thread_kill(voodoo->fifo_thread);
thread_kill(voodoo->render_thread[0]);
if (voodoo->render_threads == 2)
thread_kill(voodoo->render_thread[1]);
thread_destroy_event(voodoo->fifo_not_full_event);
thread_destroy_event(voodoo->wake_main_thread);
thread_destroy_event(voodoo->wake_render_thread);
thread_destroy_event(voodoo->wake_fifo_thread);
thread_destroy_event(voodoo->wake_render_thread[0]);
thread_destroy_event(voodoo->wake_render_thread[1]);
thread_destroy_event(voodoo->render_not_full_event[0]);
thread_destroy_event(voodoo->render_not_full_event[1]);
free(voodoo->fb_mem);
free(voodoo->tex_mem);
@ -4165,6 +4318,26 @@ static device_config_t voodoo_config[] =
.type = CONFIG_BINARY,
.default_int = 0
},
{
.name = "render_threads",
.description = "Render threads",
.type = CONFIG_SELECTION,
.selection =
{
{
.description = "1",
.value = 1
},
{
.description = "2",
.value = 2
},
{
.description = ""
}
},
.default_int = 2
},
{
.type = -1
}