ViRGE S3D improvements :
- 24 bpp mode implemented - Improved subpixel correction - fixes polygon gaps in some games - Implemented dithering - Z Update bit now has an effect - fixes Tomb Raider 2 - Improved mipmapping
This commit is contained in:
parent
2207f704dd
commit
e74519ea4e
1 changed files with 91 additions and 41 deletions
|
|
@ -15,6 +15,14 @@ static uint64_t virge_time = 0;
|
||||||
static uint64_t status_time = 0;
|
static uint64_t status_time = 0;
|
||||||
static int reg_writes = 0;
|
static int reg_writes = 0;
|
||||||
|
|
||||||
|
static int dither[4][4] =
|
||||||
|
{
|
||||||
|
0, 4, 1, 5,
|
||||||
|
6, 2, 7, 3,
|
||||||
|
1, 5, 0, 4,
|
||||||
|
7, 3, 6, 2,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct virge_t
|
typedef struct virge_t
|
||||||
{
|
{
|
||||||
mem_mapping_t linear_mapping;
|
mem_mapping_t linear_mapping;
|
||||||
|
|
@ -39,6 +47,7 @@ typedef struct virge_t
|
||||||
int is_375;
|
int is_375;
|
||||||
|
|
||||||
int bilinear_enabled;
|
int bilinear_enabled;
|
||||||
|
int dithering_enabled;
|
||||||
int memory_size;
|
int memory_size;
|
||||||
|
|
||||||
int pixel_count, tri_count;
|
int pixel_count, tri_count;
|
||||||
|
|
@ -179,6 +188,8 @@ enum
|
||||||
CMD_SET_ITA_WORD = (1 << 10),
|
CMD_SET_ITA_WORD = (1 << 10),
|
||||||
CMD_SET_ITA_DWORD = (2 << 10),
|
CMD_SET_ITA_DWORD = (2 << 10),
|
||||||
|
|
||||||
|
CMD_SET_ZUP = (1 << 23),
|
||||||
|
|
||||||
CMD_SET_ZB_MODE = (3 << 24),
|
CMD_SET_ZB_MODE = (3 << 24),
|
||||||
|
|
||||||
CMD_SET_XP = (1 << 25),
|
CMD_SET_XP = (1 << 25),
|
||||||
|
|
@ -802,7 +813,7 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p)
|
||||||
virge_t *virge = (virge_t *)p;
|
virge_t *virge = (virge_t *)p;
|
||||||
svga_t *svga = &virge->svga;
|
svga_t *svga = &virge->svga;
|
||||||
reg_writes++;
|
reg_writes++;
|
||||||
// if ((addr & 0xfffc) >= 0x8000 && (addr & 0xfffc) < 0x8400)
|
// if ((addr & 0xfffc) >= 0xb400 && (addr & 0xfffc) < 0xb800)
|
||||||
// pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
|
// pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc);
|
||||||
|
|
||||||
if ((addr & 0xfffc) < 0x8000)
|
if ((addr & 0xfffc) < 0x8000)
|
||||||
|
|
@ -1580,15 +1591,25 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RGB15_TO_24(val, r, g, b) b = (val & 0x1f) << 3; \
|
#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2); \
|
||||||
g = (val & 0x3e0) >> 2; \
|
g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \
|
||||||
r = (val & 0x7c00) >> 7
|
r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
|
||||||
|
|
||||||
#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \
|
#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \
|
||||||
g = (val & 0xff00) >> 8; \
|
g = (val & 0xff00) >> 8; \
|
||||||
r = (val & 0xff0000) >> 16
|
r = (val & 0xff0000) >> 16
|
||||||
|
|
||||||
#define RGB15(r, g, b) ((((b) >> 3) & 0x1f) | ((((g) >> 3) & 0x1f) << 5) | ((((r) >> 3) & 0x1f) << 10))
|
#define RGB15(r, g, b, dest) \
|
||||||
|
if (virge->dithering_enabled) \
|
||||||
|
{ \
|
||||||
|
int add = dither[_y & 3][_x & 3]; \
|
||||||
|
int _r = (r > 248) ? 248 : r+add; \
|
||||||
|
int _g = (g > 248) ? 248 : g+add; \
|
||||||
|
int _b = (b > 248) ? 248 : b+add; \
|
||||||
|
dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10)
|
||||||
|
|
||||||
#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16))
|
#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16))
|
||||||
|
|
||||||
|
|
@ -1774,7 +1795,9 @@ static void tex_sample_mipmap(s3d_state_t *state)
|
||||||
{
|
{
|
||||||
s3d_texture_state_t texture_state;
|
s3d_texture_state_t texture_state;
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
texture_state.u = state->u + state->tbu;
|
texture_state.u = state->u + state->tbu;
|
||||||
texture_state.v = state->v + state->tbv;
|
texture_state.v = state->v + state->tbv;
|
||||||
|
|
@ -1790,7 +1813,9 @@ static void tex_sample_mipmap_filter(s3d_state_t *state)
|
||||||
int du, dv;
|
int du, dv;
|
||||||
int d[4];
|
int d[4];
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
tex_offset = 1 << texture_state.texture_shift;
|
tex_offset = 1 << texture_state.texture_shift;
|
||||||
|
|
||||||
|
|
@ -1960,7 +1985,9 @@ static void tex_sample_persp_mipmap(s3d_state_t *state)
|
||||||
if (state->w)
|
if (state->w)
|
||||||
w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
|
w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
|
texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
|
||||||
texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
|
texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
|
||||||
|
|
@ -1983,7 +2010,9 @@ static void tex_sample_persp_mipmap_filter(s3d_state_t *state)
|
||||||
u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
|
u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu;
|
||||||
v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
|
v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv;
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
tex_offset = 1 << texture_state.texture_shift;
|
tex_offset = 1 << texture_state.texture_shift;
|
||||||
|
|
||||||
|
|
@ -2024,7 +2053,9 @@ static void tex_sample_persp_mipmap_375(s3d_state_t *state)
|
||||||
if (state->w)
|
if (state->w)
|
||||||
w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
|
w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w);
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
|
texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
|
||||||
texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
|
texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
|
||||||
|
|
@ -2047,7 +2078,9 @@ static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state)
|
||||||
u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
|
u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu;
|
||||||
v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
|
v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv;
|
||||||
|
|
||||||
texture_state.level = MAX(MIN(9 - ((state->d >> 27) & 0xf), state->max_d), 0);
|
texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf);
|
||||||
|
if (texture_state.level < 0)
|
||||||
|
texture_state.level = 0;
|
||||||
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
texture_state.texture_shift = 18 + (9 - texture_state.level);
|
||||||
tex_offset = 1 << texture_state.texture_shift;
|
tex_offset = 1 << texture_state.texture_shift;
|
||||||
|
|
||||||
|
|
@ -2185,7 +2218,7 @@ static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t
|
||||||
|
|
||||||
int y_count = yc;
|
int y_count = yc;
|
||||||
|
|
||||||
int bpp = 1;
|
int bpp = (virge->s3d.cmd_set >> 2) & 7;
|
||||||
|
|
||||||
uint32_t dest_offset, z_offset;
|
uint32_t dest_offset, z_offset;
|
||||||
|
|
||||||
|
|
@ -2223,24 +2256,33 @@ static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t
|
||||||
|
|
||||||
for (; y_count > 0; y_count--)
|
for (; y_count > 0; y_count--)
|
||||||
{
|
{
|
||||||
int x = state->x1 >> 20;
|
int x = (state->x1 + ((1 << 20) - 1)) >> 20;
|
||||||
int xe = state->x2 >> 20;
|
int xe = (state->x2 + ((1 << 20) - 1)) >> 20;
|
||||||
uint32_t z = state->base_z;
|
uint32_t z = state->base_z;
|
||||||
|
if (x_dir < 0)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
xe--;
|
||||||
|
}
|
||||||
|
|
||||||
if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))
|
if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))
|
||||||
{
|
{
|
||||||
uint32_t dest_addr, z_addr;
|
uint32_t dest_addr, z_addr;
|
||||||
int dx = (x_dir > 0) ? 8 - ((state->x1 >> 16) & 0xf) : ((state->x1 >> 16) & 0xf) - 8;
|
int dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f);
|
||||||
int x_offset = x_dir << bpp;
|
int x_offset = x_dir * (bpp + 1);
|
||||||
|
int xz_offset = x_dir << 1;
|
||||||
state->r = state->base_r + ((virge->s3d.TdRdX * dx) >> 4);
|
if (x_dir > 0)
|
||||||
state->g = state->base_g + ((virge->s3d.TdGdX * dx) >> 4);
|
dx += 1;
|
||||||
state->b = state->base_b + ((virge->s3d.TdBdX * dx) >> 4);
|
state->r = state->base_r + ((virge->s3d.TdRdX * dx) >> 5);
|
||||||
state->a = state->base_a + ((virge->s3d.TdAdX * dx) >> 4);
|
state->g = state->base_g + ((virge->s3d.TdGdX * dx) >> 5);
|
||||||
state->u = state->base_u + ((virge->s3d.TdUdX * dx) >> 4);
|
state->b = state->base_b + ((virge->s3d.TdBdX * dx) >> 5);
|
||||||
state->v = state->base_v + ((virge->s3d.TdVdX * dx) >> 4);
|
state->a = state->base_a + ((virge->s3d.TdAdX * dx) >> 5);
|
||||||
state->w = state->base_w + ((virge->s3d.TdWdX * dx) >> 4);
|
state->u = state->base_u + ((virge->s3d.TdUdX * dx) >> 5);
|
||||||
state->d = state->base_d + ((virge->s3d.TdDdX * dx) >> 4);
|
state->v = state->base_v + ((virge->s3d.TdVdX * dx) >> 5);
|
||||||
z += ((virge->s3d.TdZdX * dx) >> 4);
|
state->w = state->base_w + ((virge->s3d.TdWdX * dx) >> 5);
|
||||||
|
state->d = state->base_d + ((virge->s3d.TdDdX * dx) >> 5);
|
||||||
|
z += ((virge->s3d.TdZdX * dx) >> 5);
|
||||||
|
|
||||||
// pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4);
|
// pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4);
|
||||||
|
|
||||||
if (virge->s3d.cmd_set & CMD_SET_HC)
|
if (virge->s3d.cmd_set & CMD_SET_HC)
|
||||||
|
|
@ -2299,10 +2341,10 @@ static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t
|
||||||
|
|
||||||
virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount;
|
virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount;
|
||||||
|
|
||||||
dest_addr = dest_offset + (x << bpp);
|
dest_addr = dest_offset + (x * (bpp + 1));
|
||||||
z_addr = z_offset + (x << bpp);
|
z_addr = z_offset + (x << 1);
|
||||||
|
|
||||||
for (; x != ((xe + x_dir) & 0xfff); x = (x + x_dir) & 0xfff)
|
for (; x != xe; x = (x + x_dir) & 0xfff)
|
||||||
{
|
{
|
||||||
int update = 1;
|
int update = 1;
|
||||||
int16_t src_z;
|
int16_t src_z;
|
||||||
|
|
@ -2351,16 +2393,18 @@ static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t
|
||||||
/*Not implemented yet*/
|
/*Not implemented yet*/
|
||||||
break;
|
break;
|
||||||
case 1: /*16 bpp*/
|
case 1: /*16 bpp*/
|
||||||
dest_col = RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
|
RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col);
|
||||||
*(uint16_t *)&vram[dest_addr] = dest_col;
|
*(uint16_t *)&vram[dest_addr] = dest_col;
|
||||||
break;
|
break;
|
||||||
case 2: /*24 bpp*/
|
case 2: /*24 bpp*/
|
||||||
dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
|
dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b);
|
||||||
*(uint32_t *)&vram[dest_addr] = dest_col;
|
*(uint8_t *)&vram[dest_addr] = dest_col & 0xff;
|
||||||
|
*(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff;
|
||||||
|
*(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_z)
|
if (use_z && (virge->s3d.cmd_set & CMD_SET_ZUP))
|
||||||
Z_WRITE(z_addr, src_z);
|
Z_WRITE(z_addr, src_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2374,7 +2418,7 @@ static void tri(virge_t *virge, s3d_state_t *state, int yc, int32_t dx1, int32_t
|
||||||
state->d += virge->s3d.TdDdX;
|
state->d += virge->s3d.TdDdX;
|
||||||
state->w += virge->s3d.TdWdX;
|
state->w += virge->s3d.TdWdX;
|
||||||
dest_addr += x_offset;
|
dest_addr += x_offset;
|
||||||
z_addr += x_offset;
|
z_addr += xz_offset;
|
||||||
virge->pixel_count++;
|
virge->pixel_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2979,8 +3023,8 @@ static void *s3_virge_init()
|
||||||
memset(virge, 0, sizeof(virge_t));
|
memset(virge, 0, sizeof(virge_t));
|
||||||
|
|
||||||
virge->bilinear_enabled = device_get_config_int("bilinear");
|
virge->bilinear_enabled = device_get_config_int("bilinear");
|
||||||
|
virge->dithering_enabled = device_get_config_int("dithering");
|
||||||
virge->memory_size = device_get_config_int("memory");
|
virge->memory_size = device_get_config_int("memory");
|
||||||
pclog("bilinear_enabled=%i memory_size=%i\n", virge->bilinear_enabled, virge->memory_size);
|
|
||||||
|
|
||||||
svga_init(&virge->svga, virge, virge->memory_size << 20,
|
svga_init(&virge->svga, virge, virge->memory_size << 20,
|
||||||
s3_virge_recalctimings,
|
s3_virge_recalctimings,
|
||||||
|
|
@ -3064,8 +3108,8 @@ static void *s3_virge_375_init()
|
||||||
memset(virge, 0, sizeof(virge_t));
|
memset(virge, 0, sizeof(virge_t));
|
||||||
|
|
||||||
virge->bilinear_enabled = device_get_config_int("bilinear");
|
virge->bilinear_enabled = device_get_config_int("bilinear");
|
||||||
|
virge->dithering_enabled = device_get_config_int("dithering");
|
||||||
virge->memory_size = device_get_config_int("memory");
|
virge->memory_size = device_get_config_int("memory");
|
||||||
pclog("bilinear_enabled=%i memory_size=%i\n", virge->bilinear_enabled, virge->memory_size);
|
|
||||||
|
|
||||||
svga_init(&virge->svga, virge, virge->memory_size << 20,
|
svga_init(&virge->svga, virge, virge->memory_size << 20,
|
||||||
s3_virge_recalctimings,
|
s3_virge_recalctimings,
|
||||||
|
|
@ -3207,12 +3251,6 @@ static int s3_virge_add_status_info(char *s, int max_len, void *p)
|
||||||
|
|
||||||
static device_config_t s3_virge_config[] =
|
static device_config_t s3_virge_config[] =
|
||||||
{
|
{
|
||||||
{
|
|
||||||
.name = "bilinear",
|
|
||||||
.description = "Bilinear filtering",
|
|
||||||
.type = CONFIG_BINARY,
|
|
||||||
.default_int = 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "memory",
|
.name = "memory",
|
||||||
.description = "Memory size",
|
.description = "Memory size",
|
||||||
|
|
@ -3233,6 +3271,18 @@ static device_config_t s3_virge_config[] =
|
||||||
},
|
},
|
||||||
.default_int = 4
|
.default_int = 4
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "bilinear",
|
||||||
|
.description = "Bilinear filtering",
|
||||||
|
.type = CONFIG_BINARY,
|
||||||
|
.default_int = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "dithering",
|
||||||
|
.description = "Dithering",
|
||||||
|
.type = CONFIG_BINARY,
|
||||||
|
.default_int = 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.type = -1
|
.type = -1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue