PCem Voodoo emulation

This commit is contained in:
Toni Wilen 2020-12-19 22:31:24 +02:00
parent 87a9be1b65
commit 02dbc440b5
27 changed files with 25230 additions and 0 deletions

1470
pcem/vid_voodoo.cpp Normal file

File diff suppressed because it is too large Load Diff

1
pcem/vid_voodoo.h Normal file
View File

@ -0,0 +1 @@
extern device_t voodoo_device;

2881
pcem/vid_voodoo_banshee.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
extern device_t voodoo_banshee_device;
extern device_t creative_voodoo_banshee_device;
extern device_t voodoo_3_2000_device;
extern device_t voodoo_3_3000_device;
void banshee_set_overlay_addr(void *p, uint32_t addr);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val);

507
pcem/vid_voodoo_blitter.cpp Normal file
View File

@ -0,0 +1,507 @@
#include <math.h>
#include <stddef.h>
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_blitter.h"
#include "vid_voodoo_dither.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
enum
{
BLIT_COMMAND_SCREEN_TO_SCREEN = 0,
BLIT_COMMAND_CPU_TO_SCREEN = 1,
BLIT_COMMAND_RECT_FILL = 2,
BLIT_COMMAND_SGRAM_FILL = 3
};
enum
{
BLIT_SRC_1BPP = (0 << 3),
BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3),
BLIT_SRC_16BPP = (2 << 3),
BLIT_SRC_24BPP = (3 << 3),
BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3),
BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3)
};
enum
{
BLIT_SRC_RGB_ARGB = (0 << 6),
BLIT_SRC_RGB_ABGR = (1 << 6),
BLIT_SRC_RGB_RGBA = (2 << 6),
BLIT_SRC_RGB_BGRA = (3 << 6)
};
enum
{
BLIT_COMMAND_MASK = 7,
BLIT_SRC_FORMAT = (7 << 3),
BLIT_SRC_RGB_FORMAT = (3 << 6),
BLIT_SRC_CHROMA = (1 << 10),
BLIT_DST_CHROMA = (1 << 12),
BLIT_CLIPPING_ENABLED = (1 << 16)
};
enum
{
BLIT_ROP_DST_PASS = (1 << 0),
BLIT_ROP_SRC_PASS = (1 << 1)
};
#define MIX(src_dat, dst_dat, rop) \
switch (rop) \
{ \
case 0x0: dst_dat = 0; break; \
case 0x1: dst_dat = ~(src_dat | dst_dat); break; \
case 0x2: dst_dat = ~src_dat & dst_dat; break; \
case 0x3: dst_dat = ~src_dat; break; \
case 0x4: dst_dat = src_dat & ~dst_dat; break; \
case 0x5: dst_dat = ~dst_dat; break; \
case 0x6: dst_dat = src_dat ^ dst_dat; break; \
case 0x7: dst_dat = ~(src_dat & dst_dat); break; \
case 0x8: dst_dat = src_dat & dst_dat; break; \
case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \
case 0xa: dst_dat = dst_dat; break; \
case 0xb: dst_dat = ~src_dat | dst_dat; break; \
case 0xc: dst_dat = src_dat; break; \
case 0xd: dst_dat = src_dat | ~dst_dat; break; \
case 0xe: dst_dat = src_dat | dst_dat; break; \
case 0xf: dst_dat = 0xffff; break; \
}
void voodoo_v2_blit_start(voodoo_t *voodoo)
{
uint64_t dat64;
int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY);
int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1;
int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1;
int dst_x;
int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff;
int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8);
int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8);
uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8);
uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8);
int x, y;
/* pclog("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n",
voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/
voodoo_wait_for_render_thread_idle(voodoo);
switch (voodoo->bltCommand & BLIT_COMMAND_MASK)
{
case BLIT_COMMAND_SCREEN_TO_SCREEN:
for (y = 0; y <= size_y; y++)
{
uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride];
uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride];
int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX;
for (x = 0; x <= size_x; x++)
{
uint16_t src_dat = src[src_x];
uint16_t dst_dat = dst[dst_x];
int rop = 0;
if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED)
{
if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight ||
dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY)
goto skip_pixel_blit;
}
if (voodoo->bltCommand & BLIT_SRC_CHROMA)
{
int r = (src_dat >> 11);
int g = (src_dat >> 5) & 0x3f;
int b = src_dat & 0x1f;
if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR &&
g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG &&
b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB)
rop |= BLIT_ROP_SRC_PASS;
}
if (voodoo->bltCommand & BLIT_DST_CHROMA)
{
int r = (dst_dat >> 11);
int g = (dst_dat >> 5) & 0x3f;
int b = dst_dat & 0x1f;
if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR &&
g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG &&
b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB)
rop |= BLIT_ROP_DST_PASS;
}
MIX(src_dat, dst_dat, voodoo->bltRop[rop]);
dst[dst_x] = dst_dat;
skip_pixel_blit:
src_x += x_dir;
dst_x += x_dir;
}
src_y += y_dir;
dst_y += y_dir;
}
break;
case BLIT_COMMAND_CPU_TO_SCREEN:
voodoo->blt.dst_x = voodoo->bltDstX;
voodoo->blt.dst_y = voodoo->bltDstY;
voodoo->blt.cur_x = 0;
voodoo->blt.size_x = size_x;
voodoo->blt.size_y = size_y;
voodoo->blt.x_dir = x_dir;
voodoo->blt.y_dir = y_dir;
voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8);
break;
case BLIT_COMMAND_RECT_FILL:
for (y = 0; y <= size_y; y++)
{
uint16_t *dst;
int dst_x = voodoo->bltDstX;
if (SLI_ENABLED)
{
if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) ||
((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1)))
goto skip_line_fill;
dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride];
}
else
dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride];
for (x = 0; x <= size_x; x++)
{
if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED)
{
if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight ||
dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY)
goto skip_pixel_fill;
}
dst[dst_x] = voodoo->bltColorFg;
skip_pixel_fill:
dst_x += x_dir;
}
skip_line_fill:
dst_y += y_dir;
}
break;
case BLIT_COMMAND_SGRAM_FILL:
/*32x32 tiles - 2kb*/
dst_y = voodoo->bltDstY & 0x3ff;
size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb
size_y = voodoo->bltSizeY & 0x3ff;
dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) |
((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48);
for (y = 0; y <= size_y; y++)
{
uint64_t *dst;
/*This may be wrong*/
if (!y)
{
dst_x = voodoo->bltDstX & 0x1ff;
size_x = 511 - dst_x;
}
else if (y < size_y)
{
dst_x = 0;
size_x = 511;
}
else
{
dst_x = 0;
size_x = voodoo->bltSizeX & 0x1ff;
}
dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask];
for (x = 0; x <= size_x; x++)
dst[x] = dat64;
dst_y++;
}
break;
default:
fatal("bad blit command %08x\n", voodoo->bltCommand);
}
}
void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data)
{
int src_bits = 32;
uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8);
uint32_t addr;
uint16_t *dst;
if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN)
return;
if (SLI_ENABLED)
{
addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride;
dst = (uint16_t *)&voodoo->fb_mem[addr];
}
else
{
addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride;
dst = (uint16_t *)&voodoo->fb_mem[addr];
}
if (addr >= voodoo->front_offset && voodoo->row_width)
{
int y = (addr - voodoo->front_offset) / voodoo->row_width;
if (y < voodoo->v_disp)
voodoo->dirty_line[y] = 2;
}
while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x)
{
int r = 0, g = 0, b = 0;
uint16_t src_dat = 0, dst_dat;
int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x);
int rop = 0;
switch (voodoo->bltCommand & BLIT_SRC_FORMAT)
{
case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED:
src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg;
data >>= 1;
src_bits--;
break;
case BLIT_SRC_16BPP:
switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT)
{
case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA:
src_dat = data & 0xffff;
break;
case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA:
src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11);
break;
}
data >>= 16;
src_bits -= 16;
break;
case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4:
switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT)
{
case BLIT_SRC_RGB_ARGB:
r = (data >> 16) & 0xff;
g = (data >> 8) & 0xff;
b = data & 0xff;
break;
case BLIT_SRC_RGB_ABGR:
r = data & 0xff;
g = (data >> 8) & 0xff;
b = (data >> 16) & 0xff;
break;
case BLIT_SRC_RGB_RGBA:
r = (data >> 24) & 0xff;
g = (data >> 16) & 0xff;
b = (data >> 8) & 0xff;
break;
case BLIT_SRC_RGB_BGRA:
r = (data >> 8) & 0xff;
g = (data >> 16) & 0xff;
b = (data >> 24) & 0xff;
break;
}
switch (voodoo->bltCommand & BLIT_SRC_FORMAT)
{
case BLIT_SRC_24BPP:
src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8);
break;
case BLIT_SRC_24BPP_DITHER_2X2:
r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1];
g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1];
b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1];
src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8);
break;
case BLIT_SRC_24BPP_DITHER_4X4:
r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3];
g = dither_g[g][voodoo->blt.dst_y & 3][x & 3];
b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3];
src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8);
break;
}
src_bits = 0;
break;
}
if (SLI_ENABLED)
{
if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) ||
((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1)))
goto skip_pixel;
}
if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED)
{
if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight ||
voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY)
goto skip_pixel;
}
dst_dat = dst[x];
if (voodoo->bltCommand & BLIT_SRC_CHROMA)
{
r = (src_dat >> 11);
g = (src_dat >> 5) & 0x3f;
b = src_dat & 0x1f;
if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR &&
g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG &&
b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB)
rop |= BLIT_ROP_SRC_PASS;
}
if (voodoo->bltCommand & BLIT_DST_CHROMA)
{
r = (dst_dat >> 11);
g = (dst_dat >> 5) & 0x3f;
b = dst_dat & 0x1f;
if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR &&
g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG &&
b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB)
rop |= BLIT_ROP_DST_PASS;
}
MIX(src_dat, dst_dat, voodoo->bltRop[rop]);
dst[x] = dst_dat;
skip_pixel:
voodoo->blt.cur_x++;
}
if (voodoo->blt.cur_x > voodoo->blt.size_x)
{
voodoo->blt.size_y--;
if (voodoo->blt.size_y >= 0)
{
voodoo->blt.cur_x = 0;
voodoo->blt.dst_y += voodoo->blt.y_dir;
}
}
}
void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params)
{
int y;
int low_y, high_y;
if (params->fbzMode & (1 << 17))
{
high_y = voodoo->v_disp - params->clipLowY;
low_y = voodoo->v_disp - params->clipHighY;
}
else
{
low_y = params->clipLowY;
high_y = params->clipHighY;
}
if (params->fbzMode & FBZ_RGB_WMASK)
{
int r, g, b;
uint16_t col;
r = ((params->color1 >> 16) >> 3) & 0x1f;
g = ((params->color1 >> 8) >> 2) & 0x3f;
b = (params->color1 >> 3) & 0x1f;
col = b | (g << 5) | (r << 11);
if (SLI_ENABLED)
{
for (y = low_y; y < high_y; y += 2)
{
uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
cbuf[x] = col;
}
}
else
{
for (y = low_y; y < high_y; y++)
{
if (voodoo->col_tiled)
{
uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 5) * voodoo->row_width + (y & 31) * 128) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
{
int x2 = (x & 63) | ((x >> 6) * 128*32/2);
cbuf[x2] = col;
}
}
else
{
uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y * voodoo->row_width) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
cbuf[x] = col;
}
}
}
}
if (params->fbzMode & FBZ_DEPTH_WMASK)
{
if (SLI_ENABLED)
{
for (y = low_y; y < high_y; y += 2)
{
uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
abuf[x] = params->zaColor & 0xffff;
}
}
else
{
for (y = low_y; y < high_y; y++)
{
if (voodoo->aux_tiled)
{
uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 5) * voodoo->aux_row_width + (y & 31) * 128) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
{
int x2 = (x & 63) | ((x >> 6) * 128*32/2);
abuf[x2] = params->zaColor & 0xffff;
}
}
else
{
uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y * voodoo->aux_row_width) & voodoo->fb_mask];
int x;
for (x = params->clipLeft; x < params->clipRight; x++)
abuf[x] = params->zaColor & 0xffff;
}
}
}
}
}

View File

@ -0,0 +1,3 @@
void voodoo_v2_blit_start(voodoo_t *voodoo);
void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data);
void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

509
pcem/vid_voodoo_common.h Normal file
View File

@ -0,0 +1,509 @@
#ifdef MIN
#undef MIN
#endif
#ifdef CLAMP
#undef CLAMP
#endif
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x)))
#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x)))
#define LOD_MAX 8
#define TEX_DIRTY_SHIFT 10
#define TEX_CACHE_MAX 64
enum
{
VOODOO_1 = 0,
VOODOO_SB50,
VOODOO_2,
VOODOO_BANSHEE,
VOODOO_3
};
typedef union int_float
{
uint32_t i;
float f;
} int_float;
typedef struct rgb_t
{
uint8_t b, g, r;
uint8_t pad;
} rgb_t;
typedef struct rgba8_t
{
uint8_t b, g, r, a;
} rgba8_t;
typedef union rgba_u
{
struct
{
uint8_t b, g, r, a;
} rgba;
uint32_t u;
} rgba_u;
#define FIFO_SIZE 65536
#define FIFO_MASK (FIFO_SIZE - 1)
#define FIFO_ENTRY_SIZE (1 << 31)
#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx)
#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE-4)
#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx)
#define FIFO_TYPE 0xff000000
#define FIFO_ADDR 0x00ffffff
enum
{
FIFO_INVALID = (0x00 << 24),
FIFO_WRITEL_REG = (0x01 << 24),
FIFO_WRITEW_FB = (0x02 << 24),
FIFO_WRITEL_FB = (0x03 << 24),
FIFO_WRITEL_TEX = (0x04 << 24),
FIFO_WRITEL_2DREG = (0x05 << 24)
};
#define PARAM_SIZE 1024
#define PARAM_MASK (PARAM_SIZE - 1)
#define PARAM_ENTRY_SIZE (1 << 31)
#define PARAM_ENTRIES(x) (voodoo->params_write_idx - voodoo->params_read_idx[x])
#define PARAM_FULL(x) ((voodoo->params_write_idx - voodoo->params_read_idx[x]) >= PARAM_SIZE)
#define PARAM_EMPTY(x) (voodoo->params_read_idx[x] == voodoo->params_write_idx)
typedef struct
{
uint32_t addr_type;
uint32_t val;
} fifo_entry_t;
typedef struct voodoo_params_t
{
int command;
int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy;
uint32_t startR, startG, startB, startZ, startA;
int32_t dBdX, dGdX, dRdX, dAdX, dZdX;
int32_t dBdY, dGdY, dRdY, dAdY, dZdY;
int64_t startW, dWdX, dWdY;
struct
{
int64_t startS, startT, startW, p1;
int64_t dSdX, dTdX, dWdX, p2;
int64_t dSdY, dTdY, dWdY, p3;
} tmu[2];
uint32_t color0, color1;
uint32_t fbzMode;
uint32_t fbzColorPath;
uint32_t fogMode;
rgb_t fogColor;
struct
{
uint8_t fog, dfog;
} fogTable[64];
uint32_t alphaMode;
uint32_t zaColor;
int chromaKey_r, chromaKey_g, chromaKey_b;
uint32_t chromaKey;
uint32_t textureMode[2];
uint32_t tLOD[2];
uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2];
uint32_t tex_base[2][LOD_MAX+2];
uint32_t tex_end[2][LOD_MAX+2];
int tex_width[2];
int tex_w_mask[2][LOD_MAX+2];
int tex_w_nmask[2][LOD_MAX+2];
int tex_h_mask[2][LOD_MAX+2];
int tex_shift[2][LOD_MAX+2];
int tex_lod[2][LOD_MAX+2];
int tex_entry[2];
int detail_max[2], detail_bias[2], detail_scale[2];
uint32_t draw_offset, aux_offset;
int tformat[2];
int clipLeft, clipRight, clipLowY, clipHighY;
int clipLeft1, clipRight1, clipLowY1, clipHighY1;
int sign;
uint32_t front_offset;
uint32_t swapbufferCMD;
uint32_t stipple;
int col_tiled, aux_tiled;
int row_width, aux_row_width;
} voodoo_params_t;
typedef struct texture_t
{
uint32_t base;
uint32_t tLOD;
volatile int refcount, refcount_r[4];
int is16;
uint32_t palette_checksum;
uint32_t addr_start[4], addr_end[4];
uint32_t *data;
} texture_t;
typedef struct vert_t
{
float sVx, sVy;
float sRed, sGreen, sBlue, sAlpha;
float sVz, sWb;
float sW0, sS0, sT0;
float sW1, sS1, sT1;
} vert_t;
typedef struct clip_t
{
int x_min, x_max;
int y_min, y_max;
} clip_t;
typedef struct voodoo_t
{
mem_mapping_t mapping;
int pci_enable;
uint8_t dac_data[8];
int dac_reg, dac_reg_ff;
uint8_t dac_readdata;
uint16_t dac_pll_regs[16];
float pixel_clock;
uint64_t line_time;
voodoo_params_t params;
uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4;
uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/
uint32_t initEnable;
uint32_t lfbMode;
uint32_t memBaseAddr;
int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy;
uint32_t front_offset, back_offset;
uint32_t fb_read_offset, fb_write_offset;
int row_width, aux_row_width;
int block_width;
int col_tiled, aux_tiled;
uint8_t *fb_mem, *tex_mem[2];
uint16_t *tex_mem_w[2];
int rgb_sel;
uint32_t trexInit1[2];
uint32_t tmuConfig;
mutex_t *swap_mutex;
int swap_count;
int disp_buffer, draw_buffer;
pc_timer_t timer;
int line;
svga_t *svga;
uint32_t backPorch;
uint32_t videoDimensions;
uint32_t hSync, vSync;
int h_total, v_total, v_disp;
int h_disp;
int v_retrace;
struct
{
uint32_t y[4], i[4], q[4];
} nccTable[2][2];
rgba_u palette[2][256];
rgba_u ncc_lookup[2][2][256];
int ncc_dirty[2];
thread_t *fifo_thread;
thread_t *render_thread[4];
event_t *wake_fifo_thread;
event_t *wake_main_thread;
event_t *fifo_not_full_event;
event_t *render_not_full_event[4];
event_t *wake_render_thread[4];
int voodoo_busy;
int render_voodoo_busy[4];
int render_threads;
int odd_even_mask;
int pixel_count[4], texel_count[4], tri_count, frame_count;
int pixel_count_old[4], texel_count_old[4];
int wr_count, rd_count, tex_count;
int retrace_count;
int swap_interval;
uint32_t swap_offset;
int swap_pending;
int bilinear_enabled;
int fb_size;
uint32_t fb_mask;
int texture_size;
uint32_t texture_mask;
int dual_tmus;
int type;
fifo_entry_t fifo[FIFO_SIZE];
volatile int fifo_read_idx, fifo_write_idx;
volatile int cmd_read, cmd_written, cmd_written_fifo;
voodoo_params_t params_buffer[PARAM_SIZE];
volatile int params_read_idx[4], params_write_idx;
uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size;
int cmdfifo_rp, cmdfifo_ret_addr;
int cmdfifo_in_sub;
volatile int cmdfifo_depth_rd, cmdfifo_depth_wr;
volatile int cmdfifo_enabled;
uint32_t cmdfifo_amin, cmdfifo_amax;
int cmdfifo_holecount;
uint32_t sSetupMode;
vert_t verts[4];
unsigned int vertex_ages[3];
unsigned int vertex_next_age;
int num_verticies;
int cull_pingpong;
int flush;
int scrfilter;
int scrfilterEnabled;
int scrfilterThreshold;
int scrfilterThresholdOld;
uint32_t last_write_addr;
uint32_t fbiPixelsIn;
uint32_t fbiChromaFail;
uint32_t fbiZFuncFail;
uint32_t fbiAFuncFail;
uint32_t fbiPixelsOut;
uint32_t bltSrcBaseAddr;
uint32_t bltDstBaseAddr;
int bltSrcXYStride, bltDstXYStride;
uint32_t bltSrcChromaRange, bltDstChromaRange;
int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB;
int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB;
int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB;
int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB;
int bltClipRight, bltClipLeft;
int bltClipHighY, bltClipLowY;
int bltSrcX, bltSrcY;
int bltDstX, bltDstY;
int bltSizeX, bltSizeY;
int bltRop[4];
uint16_t bltColorFg, bltColorBg;
uint32_t bltCommand;
uint32_t leftOverlayBuf;
struct
{
int dst_x, dst_y;
int cur_x;
int size_x, size_y;
int x_dir, y_dir;
int dst_stride;
} blt;
struct
{
uint32_t bresError0, bresError1;
uint32_t clip0Min, clip0Max;
uint32_t clip1Min, clip1Max;
uint32_t colorBack, colorFore;
uint32_t command, commandExtra;
uint32_t dstBaseAddr;
uint32_t dstFormat;
uint32_t dstSize;
uint32_t dstXY;
uint32_t lineStipple;
uint32_t lineStyle;
uint32_t rop;
uint32_t srcBaseAddr;
uint32_t srcFormat;
uint32_t srcSize;
uint32_t srcXY;
uint32_t colorPattern[64];
int bres_error_0, bres_error_1;
uint32_t colorPattern8[64], colorPattern16[64], colorPattern24[64];
int cur_x, cur_y;
uint32_t dstBaseAddr_tiled;
uint32_t dstColorkeyMin, dstColorkeyMax;
int dstSizeX, dstSizeY;
int dstX, dstY;
int dst_stride;
int patoff_x, patoff_y;
uint8_t rops[4];
uint32_t srcBaseAddr_tiled;
uint32_t srcColorkeyMin, srcColorkeyMax;
int srcSizeX, srcSizeY;
int srcX, srcY;
int src_stride;
int old_srcX;
/*Used for handling packed 24bpp host data*/
int host_data_remainder;
uint32_t old_host_data;
/*Polyfill coordinates*/
int lx[2], rx[2];
int ly[2], ry[2];
/*Polyfill state*/
int error[2];
int dx[2], dy[2];
int x_inc[2]; /*y_inc is always 1 for polyfill*/
int lx_cur, rx_cur;
clip_t clip[2];
uint8_t host_data[16384];
int host_data_count;
int host_data_size_src, host_data_size_dest;
int src_stride_src, src_stride_dest;
int src_bpp;
int line_pix_pos, line_bit_pos;
int line_rep_cnt, line_bit_mask_size;
} banshee_blt;
struct
{
uint32_t vidOverlayStartCoords;
uint32_t vidOverlayEndScreenCoords;
uint32_t vidOverlayDudx, vidOverlayDudxOffsetSrcWidth;
uint32_t vidOverlayDvdy, vidOverlayDvdyOffset;
//uint32_t vidDesktopOverlayStride;
int start_x, start_y;
int end_x, end_y;
int size_x, size_y;
int overlay_bytes;
unsigned int src_y;
} overlay;
rgb_t clutData[33];
int clutData_dirty;
rgb_t clutData256[256];
uint32_t video_16to32[0x10000];
uint8_t dirty_line[2048];
int dirty_line_low, dirty_line_high;
int fb_write_buffer, fb_draw_buffer;
int buffer_cutoff;
uint32_t tile_base, tile_stride;
int tile_stride_shift, tile_x, tile_x_real;
int read_time, write_time, burst_time;
pc_timer_t wake_timer;
/* screen filter tables */
uint8_t thefilter[256][256];
uint8_t thefilterg[256][256];
uint8_t thefilterb[256][256];
uint16_t purpleline[256][3];
texture_t texture_cache[2][TEX_CACHE_MAX];
uint8_t texture_present[2][16384];
int texture_last_removed;
uint32_t palette_checksum[2];
int palette_dirty[2];
uint64_t time;
int render_time[4];
int use_recompiler;
void *codegen_data;
struct voodoo_set_t *set;
uint8_t *vram, *changedvram;
void *p;
} voodoo_t;
typedef struct voodoo_set_t
{
voodoo_t *voodoos[2];
mem_mapping_t snoop_mapping;
int nr_cards;
} voodoo_set_t;
extern rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000];
void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg);
void voodoo_recalc(voodoo_t *voodoo);
void voodoo_update_ncc(voodoo_t *voodoo, int tmu);
void *voodoo_2d3d_card_init(int type);
void voodoo_card_close(voodoo_t *voodoo);

609
pcem/vid_voodoo_display.cpp Normal file
View File

@ -0,0 +1,609 @@
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_display.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
void voodoo_update_ncc(voodoo_t *voodoo, int tmu)
{
int tbl;
for (tbl = 0; tbl < 2; tbl++)
{
int col;
for (col = 0; col < 256; col++)
{
int y = (col >> 4), i = (col >> 2) & 3, q = col & 3;
int i_r, i_g, i_b;
int q_r, q_g, q_b;
y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff;
i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff;
if (i_r & 0x100)
i_r |= 0xfffffe00;
i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff;
if (i_g & 0x100)
i_g |= 0xfffffe00;
i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff;
if (i_b & 0x100)
i_b |= 0xfffffe00;
q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff;
if (q_r & 0x100)
q_r |= 0xfffffe00;
q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff;
if (q_g & 0x100)
q_g |= 0xfffffe00;
q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff;
if (q_b & 0x100)
q_b |= 0xfffffe00;
voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r);
voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g);
voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b);
voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff;
}
}
}
void voodoo_pixelclock_update(voodoo_t *voodoo)
{
int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2;
int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2;
int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07);
float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2);
double clock_const;
int line_length;
if ((voodoo->dac_data[6] & 0xf0) == 0x20 ||
(voodoo->dac_data[6] & 0xf0) == 0x60 ||
(voodoo->dac_data[6] & 0xf0) == 0x70)
t /= 2.0f;
line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff);
// pclog("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length);
voodoo->pixel_clock = t;
clock_const = cpuclock / t;
voodoo->line_time = (uint64_t)((double)line_length * clock_const * (double)(1ull << 32));
}
static void voodoo_calc_clutData(voodoo_t *voodoo)
{
int c;
for (c = 0; c < 256; c++)
{
voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) +
voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3;
voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) +
voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3;
voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) +
voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3;
}
for (c = 0; c < 65536; c++)
{
int r = (c >> 8) & 0xf8;
int g = (c >> 3) & 0xfc;
int b = (c << 3) & 0xf8;
// r |= (r >> 5);
// g |= (g >> 6);
// b |= (b >> 5);
voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b;
}
}
#define FILTDIV 256
static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */
void voodoo_generate_filter_v1(voodoo_t *voodoo)
{
int g, h;
float difference, diffg, diffb;
float thiscol, thiscolg, thiscolb, lined;
float fcr, fcg, fcb;
fcr = FILTCAP * 5;
fcg = FILTCAPG * 6;
fcb = FILTCAPB * 5;
for (g=0;g<FILTDIV;g++) // pixel 1
{
for (h=0;h<FILTDIV;h++) // pixel 2
{
difference = (float)(h - g);
diffg = difference;
diffb = difference;
thiscol = thiscolg = thiscolb = g;
if (difference > FILTCAP)
difference = FILTCAP;
if (difference < -FILTCAP)
difference = -FILTCAP;
if (diffg > FILTCAPG)
diffg = FILTCAPG;
if (diffg < -FILTCAPG)
diffg = -FILTCAPG;
if (diffb > FILTCAPB)
diffb = FILTCAPB;
if (diffb < -FILTCAPB)
diffb = -FILTCAPB;
// hack - to make it not bleed onto black
//if (g == 0){
//difference = diffg = diffb = 0;
//}
if ((difference < fcr) || (-difference > -fcr))
thiscol = g + (difference / 2);
if ((diffg < fcg) || (-diffg > -fcg))
thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */
if ((diffb < fcb) || (-diffb > -fcb))
thiscolb = g + (diffb / 2);
if (thiscol < 0)
thiscol = 0;
if (thiscol > FILTDIV-1)
thiscol = FILTDIV-1;
if (thiscolg < 0)
thiscolg = 0;
if (thiscolg > FILTDIV-1)
thiscolg = FILTDIV-1;
if (thiscolb < 0)
thiscolb = 0;
if (thiscolb > FILTDIV-1)
thiscolb = FILTDIV-1;
voodoo->thefilter[g][h] = thiscol;
voodoo->thefilterg[g][h] = thiscolg;
voodoo->thefilterb[g][h] = thiscolb;
}
lined = g + 4;
if (lined > 255)
lined = 255;
voodoo->purpleline[g][0] = lined;
voodoo->purpleline[g][2] = lined;
lined = g + 0;
if (lined > 255)
lined = 255;
voodoo->purpleline[g][1] = lined;
}
}
void voodoo_generate_filter_v2(voodoo_t *voodoo)
{
int g, h;
float difference;
float thiscol, thiscolg, thiscolb;
float clr, clg, clb = 0;
float fcr, fcg, fcb = 0;
// pre-clamping
fcr = FILTCAP;
fcg = FILTCAPG;
fcb = FILTCAPB;
if (fcr > 32) fcr = 32;
if (fcg > 32) fcg = 32;
if (fcb > 32) fcb = 32;
for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into
{
for (h=0;h<256;h++) // pixel 2 - our main pixel
{
float avg;
float avgdiff;
difference = (float)(g - h);
avg = (float)((g + g + g + g + h) / 5);
avgdiff = avg - (float)((g + h + h + h + h) / 5);
if (avgdiff < 0) avgdiff *= -1;
if (difference < 0) difference *= -1;
thiscol = thiscolg = thiscolb = g;
// try lighten
if (h > g)
{
clr = clg = clb = avgdiff;
if (clr>fcr) clr=fcr;
if (clg>fcg) clg=fcg;
if (clb>fcb) clb=fcb;
thiscol = g + clr;
thiscolg = g + clg;
thiscolb = g + clb;
if (thiscol>g+FILTCAP)
thiscol=g+FILTCAP;
if (thiscolg>g+FILTCAPG)
thiscolg=g+FILTCAPG;
if (thiscolb>g+FILTCAPB)
thiscolb=g+FILTCAPB;
if (thiscol>g+avgdiff)
thiscol=g+avgdiff;
if (thiscolg>g+avgdiff)
thiscolg=g+avgdiff;
if (thiscolb>g+avgdiff)
thiscolb=g+avgdiff;
}
if (difference > FILTCAP)
thiscol = g;
if (difference > FILTCAPG)
thiscolg = g;
if (difference > FILTCAPB)
thiscolb = g;
// clamp
if (thiscol < 0) thiscol = 0;
if (thiscolg < 0) thiscolg = 0;
if (thiscolb < 0) thiscolb = 0;
if (thiscol > 255) thiscol = 255;
if (thiscolg > 255) thiscolg = 255;
if (thiscolb > 255) thiscolb = 255;
// add to the table
voodoo->thefilter[g][h] = (thiscol);
voodoo->thefilterg[g][h] = (thiscolg);
voodoo->thefilterb[g][h] = (thiscolb);
// debug the ones that don't give us much of a difference
//if (difference < FILTCAP)
//pclog("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb);
}
}
}
void voodoo_threshold_check(voodoo_t *voodoo)
{
int r, g, b;
if (!voodoo->scrfilterEnabled)
return; /* considered disabled; don't check and generate */
/* Check for changes, to generate anew table */
if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld)
{
r = (voodoo->scrfilterThreshold >> 16) & 0xFF;
g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF;
b = voodoo->scrfilterThreshold & 0xFF;
FILTCAP = r;
FILTCAPG = g;
FILTCAPB = b;
pclog("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b);
voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold;
if (voodoo->type == VOODOO_2)
voodoo_generate_filter_v2(voodoo);
else
voodoo_generate_filter_v1(voodoo);
if (voodoo->type >= VOODOO_BANSHEE)
voodoo_generate_vb_filters(voodoo, FILTCAP, FILTCAPG);
}
}
static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line)
{
int x;
// Scratchpad for avoiding feedback streaks
uint8_t fil3[(voodoo->h_disp) * 3];
/* 16 to 32-bit */
for (x=0; x<column;x++)
{
fil[x*3] = ((src[x] & 31) << 3);
fil[x*3+1] = (((src[x] >> 5) & 63) << 2);
fil[x*3+2] = (((src[x] >> 11) & 31) << 3);
// Copy to our scratchpads
fil3[x*3+0] = fil[x*3+0];
fil3[x*3+1] = fil[x*3+1];
fil3[x*3+2] = fil[x*3+2];
}
/* lines */
if (line & 1)
{
for (x=0; x<column;x++)
{
fil[x*3] = voodoo->purpleline[fil[x*3]][0];
fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1];
fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2];
}
}
/* filtering time */
for (x=1; x<column;x++)
{
fil3[(x)*3] = voodoo->thefilterb[fil[x*3]][fil[ (x-1) *3]];
fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]];
fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]];
}
for (x=1; x<column;x++)
{
fil[(x)*3] = voodoo->thefilterb[fil3[x*3]][fil3[ (x-1) *3]];
fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]];
fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]];
}
for (x=1; x<column;x++)
{
fil3[(x)*3] = voodoo->thefilterb[fil[x*3]][fil[ (x-1) *3]];
fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]];
fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]];
}
for (x=0; x<column-1;x++)
{
fil[(x)*3] = voodoo->thefilterb[fil3[x*3]][fil3[ (x+1) *3]];
fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]];
fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]];
}
}
static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line)
{
int x;
// Scratchpad for blending filter
uint8_t fil3[(voodoo->h_disp) * 3];
/* 16 to 32-bit */
for (x=0; x<column;x++)
{
// Blank scratchpads
fil3[x*3+0] = fil[x*3+0] = ((src[x] & 31) << 3);
fil3[x*3+1] = fil[x*3+1] = (((src[x] >> 5) & 63) << 2);
fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3);
}
/* filtering time */
for (x=1; x<column-3;x++)
{
fil3[(x+3)*3] = voodoo->thefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)];
fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)];
fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)];
fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)];
fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)];
fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)];
fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)];
fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)];
fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)];
fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)];
fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)];
fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)];
}
// unroll for edge cases
fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)];
fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)];
fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)];
fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)];
fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)];
fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)];
fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)];
fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)];
fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)];
fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)];
fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)];
fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)];
fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)];
fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)];
fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)];
fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)];
fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)];
fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)];
}
void voodoo_callback(void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
{
if (voodoo->line < voodoo->v_disp)
{
voodoo_t *draw_voodoo;
int draw_line;
if (SLI_ENABLED)
{
if (voodoo == voodoo->set->voodoos[1])
goto skip_draw;
if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1))
draw_voodoo = voodoo;
else
draw_voodoo = voodoo->set->voodoos[1];
draw_line = voodoo->line >> 1;
}
else
{
if (!(voodoo->fbiInit0 & 1))
goto skip_draw;
draw_voodoo = voodoo;
draw_line = voodoo->line;
}
if (draw_voodoo->dirty_line[draw_line])
{
uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32];
uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width];
int x;
draw_voodoo->dirty_line[draw_line] = 0;
if (voodoo->line < voodoo->dirty_line_low)
{
voodoo->dirty_line_low = voodoo->line;
video_wait_for_buffer();
}
if (voodoo->line > voodoo->dirty_line_high)
voodoo->dirty_line_high = voodoo->line;
if (voodoo->scrfilter && voodoo->scrfilterEnabled)
{
uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */
if (voodoo->type == VOODOO_2)
voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line);
else
voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line);
for (x = 0; x < voodoo->h_disp; x++)
{
p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16);
}
}
else
{
for (x = 0; x < voodoo->h_disp; x++)
{
p[x] = draw_voodoo->video_16to32[src[x]];
}
}
}
}
}
skip_draw:
if (voodoo->line == voodoo->v_disp)
{
// pclog("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending);
voodoo->retrace_count++;
if (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC)
{
if (voodoo == voodoo->set->voodoos[0])
{
voodoo_t *voodoo_1 = voodoo->set->voodoos[1];
thread_lock_mutex(voodoo->swap_mutex);
/*Only swap if both Voodoos are waiting for buffer swap*/
if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) &&
voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval))
{
memset(voodoo->dirty_line, 1, 1024);
voodoo->retrace_count = 0;
voodoo->front_offset = voodoo->swap_offset;
if (voodoo->swap_count > 0)
voodoo->swap_count--;
voodoo->swap_pending = 0;
memset(voodoo_1->dirty_line, 1, 1024);
voodoo_1->retrace_count = 0;
voodoo_1->front_offset = voodoo_1->swap_offset;
if (voodoo_1->swap_count > 0)
voodoo_1->swap_count--;
voodoo_1->swap_pending = 0;
thread_unlock_mutex(voodoo->swap_mutex);
thread_set_event(voodoo->wake_fifo_thread);
thread_set_event(voodoo_1->wake_fifo_thread);
voodoo->frame_count++;
voodoo_1->frame_count++;
}
else
thread_unlock_mutex(voodoo->swap_mutex);
}
}
else
{
thread_lock_mutex(voodoo->swap_mutex);
if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval))
{
voodoo->front_offset = voodoo->swap_offset;
if (voodoo->swap_count > 0)
voodoo->swap_count--;
voodoo->swap_pending = 0;
thread_unlock_mutex(voodoo->swap_mutex);
memset(voodoo->dirty_line, 1, 1024);
voodoo->retrace_count = 0;
thread_set_event(voodoo->wake_fifo_thread);
voodoo->frame_count++;
}
else
thread_unlock_mutex(voodoo->swap_mutex);
}
voodoo->v_retrace = 1;
}
voodoo->line++;
if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
{
if (voodoo->line == voodoo->v_disp)
{
if (voodoo->dirty_line_high > voodoo->dirty_line_low)
svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp-1, voodoo->svga);
if (voodoo->clutData_dirty)
{
voodoo->clutData_dirty = 0;
voodoo_calc_clutData(voodoo);
}
voodoo->dirty_line_high = -1;
voodoo->dirty_line_low = 2000;
}
}
if (voodoo->line >= voodoo->v_total)
{
voodoo->line = 0;
voodoo->v_retrace = 0;
}
if (voodoo->line_time)
timer_advance_u64(&voodoo->timer, voodoo->line_time);
else
timer_advance_u64(&voodoo->timer, TIMER_USEC * 32);
}

View File

@ -0,0 +1,6 @@
void voodoo_update_ncc(voodoo_t *voodoo, int tmu);
void voodoo_pixelclock_update(voodoo_t *voodoo);
void voodoo_generate_filter_v1(voodoo_t *voodoo);
void voodoo_generate_filter_v2(voodoo_t *voodoo);
void voodoo_threshold_check(voodoo_t *voodoo);
void voodoo_callback(void *p);

5136
pcem/vid_voodoo_dither.h Normal file

File diff suppressed because it is too large Load Diff

447
pcem/vid_voodoo_fb.cpp Normal file
View File

@ -0,0 +1,447 @@
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_dither.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
#include "vid_voodoo_fb.h"
uint16_t voodoo_fb_readw(uint32_t addr, void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
int x, y;
uint32_t read_addr;
uint16_t temp;
if (voodoo->type >= VOODOO_BANSHEE)
{
x = addr & 0xffe;
y = (addr >> 12) & 0x3ff;
}
else
{
x = addr & 0x7fe;
y = (addr >> 11) & 0x3ff;
}
if (SLI_ENABLED)
{
voodoo_set_t *set = voodoo->set;
if (y & 1)
voodoo = set->voodoos[1];
else
voodoo = set->voodoos[0];
y >>= 1;
}
if (voodoo->col_tiled)
read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width);
if (read_addr > voodoo->fb_mask)
return 0xffff;
temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]);
// pclog("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++);
return temp;
}
uint32_t voodoo_fb_readl(uint32_t addr, void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
int x, y;
uint32_t read_addr;
uint32_t temp;
if (voodoo->type >= VOODOO_BANSHEE)
{
x = addr & 0xffe;
y = (addr >> 12) & 0x3ff;
}
else
{
x = addr & 0x7fe;
y = (addr >> 11) & 0x3ff;
}
if (SLI_ENABLED)
{
voodoo_set_t *set = voodoo->set;
if (y & 1)
voodoo = set->voodoos[1];
else
voodoo = set->voodoos[0];
y >>= 1;
}
if (voodoo->col_tiled)
read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width);
if (read_addr > voodoo->fb_mask)
return 0xffffffff;
temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]);
// pclog("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width);
return temp;
}
static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y)
{
int r, g, b;
if (dither)
{
if (dither2x2)
{
r = dither_rb2x2[col.r][y & 1][x & 1];
g = dither_g2x2[col.g][y & 1][x & 1];
b = dither_rb2x2[col.b][y & 1][x & 1];
}
else
{
r = dither_rb[col.r][y & 3][x & 3];
g = dither_g[col.g][y & 3][x & 3];
b = dither_rb[col.b][y & 3][x & 3];
}
}
else
{
r = col.r >> 3;
g = col.g >> 2;
b = col.b >> 3;
}
return b | (g << 5) | (r << 11);
}
void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
voodoo_params_t *params = &voodoo->params;
int x, y;
uint32_t write_addr, write_addr_aux;
rgba8_t colour_data;
uint16_t depth_data;
uint8_t alpha_data;
int write_mask = 0;
colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0;
depth_data = voodoo->params.zaColor & 0xffff;
alpha_data = voodoo->params.zaColor >> 24;
// while (!RB_EMPTY)
// thread_reset_event(voodoo->not_full_event);
// pclog("voodoo_fb_writew : %08X %04X\n", addr, val);
switch (voodoo->lfbMode & LFB_FORMAT_MASK)
{
case LFB_FORMAT_RGB565:
colour_data = rgb565[val];
alpha_data = 0xff;
write_mask = LFB_WRITE_COLOUR;
break;
case LFB_FORMAT_RGB555:
colour_data = argb1555[val];
alpha_data = 0xff;
write_mask = LFB_WRITE_COLOUR;
break;
case LFB_FORMAT_ARGB1555:
colour_data = argb1555[val];
alpha_data = colour_data.a;
write_mask = LFB_WRITE_COLOUR;
break;
case LFB_FORMAT_DEPTH:
depth_data = val;
write_mask = LFB_WRITE_DEPTH;
break;
default:
fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode);
}
if (voodoo->type >= VOODOO_BANSHEE)
{
x = addr & 0xffe;
y = (addr >> 12) & 0x3ff;
}
else
{
x = addr & 0x7fe;
y = (addr >> 11) & 0x3ff;
}
if (SLI_ENABLED)
{
if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) ||
((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1)))
return;
y >>= 1;
}
if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048)
voodoo->dirty_line[y] = 1;
if (voodoo->col_tiled)
write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width);
if (voodoo->aux_tiled)
write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width);
// pclog("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr);
if (voodoo->lfbMode & 0x100)
{
{
rgba8_t write_data = colour_data;
uint16_t new_depth = depth_data;
if (params->fbzMode & FBZ_DEPTH_ENABLE)
{
uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]);
DEPTH_TEST(new_depth);
}
if ((params->fbzMode & FBZ_CHROMAKEY) &&
write_data.r == params->chromaKey_r &&
write_data.g == params->chromaKey_g &&
write_data.b == params->chromaKey_b)
goto skip_pixel;
if (params->fogMode & FOG_ENABLE)
{
int32_t z = new_depth << 12;
int64_t w_depth = (int64_t)(int32_t)new_depth;
int32_t ia = alpha_data << 12;
APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth);
}
if (params->alphaMode & 1)
ALPHA_TEST(alpha_data);
if (params->alphaMode & (1 << 4))
{
uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]);
int dest_r, dest_g, dest_b, dest_a;
dest_r = (dat >> 8) & 0xf8;
dest_g = (dat >> 3) & 0xfc;
dest_b = (dat << 3) & 0xf8;
dest_r |= (dest_r >> 5);
dest_g |= (dest_g >> 6);
dest_b |= (dest_b >> 5);
dest_a = 0xff;
ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data);
}
if (params->fbzMode & FBZ_RGB_WMASK)
*(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y);
if (params->fbzMode & FBZ_DEPTH_WMASK)
*(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth;
skip_pixel:
x = x;
}
}
else
{
if (write_mask & LFB_WRITE_COLOUR)
*(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y);
if (write_mask & LFB_WRITE_DEPTH)
*(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data;
}
}
void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
voodoo_params_t *params = &voodoo->params;
int x, y;
uint32_t write_addr, write_addr_aux;
rgba8_t colour_data[2];
uint16_t depth_data[2];
uint8_t alpha_data[2];
int write_mask = 0, count = 1;
depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff;
alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24;
// while (!RB_EMPTY)
// thread_reset_event(voodoo->not_full_event);
// pclog("voodoo_fb_writel : %08X %08X\n", addr, val);
switch (voodoo->lfbMode & LFB_FORMAT_MASK)
{
case LFB_FORMAT_RGB565:
colour_data[0] = rgb565[val & 0xffff];
colour_data[1] = rgb565[val >> 16];
write_mask = LFB_WRITE_COLOUR;
count = 2;
break;
case LFB_FORMAT_RGB555:
colour_data[0] = argb1555[val & 0xffff];
colour_data[1] = argb1555[val >> 16];
write_mask = LFB_WRITE_COLOUR;
count = 2;
break;
case LFB_FORMAT_ARGB1555:
colour_data[0] = argb1555[val & 0xffff];
alpha_data[0] = colour_data[0].a;
colour_data[1] = argb1555[val >> 16];
alpha_data[1] = colour_data[1].a;
write_mask = LFB_WRITE_COLOUR;
count = 2;
break;
case LFB_FORMAT_ARGB8888:
colour_data[0].b = val & 0xff;
colour_data[0].g = (val >> 8) & 0xff;
colour_data[0].r = (val >> 16) & 0xff;
alpha_data[0] = (val >> 24) & 0xff;
write_mask = LFB_WRITE_COLOUR;
addr >>= 1;
break;
case LFB_FORMAT_DEPTH:
depth_data[0] = val;
depth_data[1] = val >> 16;
write_mask = LFB_WRITE_DEPTH;
count = 2;
break;
default:
fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode);
}
if (voodoo->type >= VOODOO_BANSHEE)
{
x = addr & 0xffe;
y = (addr >> 12) & 0x3ff;
}
else
{
x = addr & 0x7fe;
y = (addr >> 11) & 0x3ff;
}
if (SLI_ENABLED)
{
if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) ||
((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1)))
return;
y >>= 1;
}
if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048)
voodoo->dirty_line[y] = 1;
if (voodoo->col_tiled)
write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width);
if (voodoo->aux_tiled)
write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width;
else
write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width);
// pclog("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset);
if (voodoo->lfbMode & 0x100)
{
int c;
for (c = 0; c < count; c++)
{
rgba8_t write_data = colour_data[c];
uint16_t new_depth = depth_data[c];
if (params->fbzMode & FBZ_DEPTH_ENABLE)
{
uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]);
DEPTH_TEST(new_depth);
}
if ((params->fbzMode & FBZ_CHROMAKEY) &&
write_data.r == params->chromaKey_r &&
write_data.g == params->chromaKey_g &&
write_data.b == params->chromaKey_b)
goto skip_pixel;
if (params->fogMode & FOG_ENABLE)
{
int32_t z = new_depth << 12;
int64_t w_depth = new_depth;
int32_t ia = alpha_data[c] << 12;
APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth);
}
if (params->alphaMode & 1)
ALPHA_TEST(alpha_data[c]);
if (params->alphaMode & (1 << 4))
{
uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]);
int dest_r, dest_g, dest_b, dest_a;
dest_r = (dat >> 8) & 0xf8;
dest_g = (dat >> 3) & 0xfc;
dest_b = (dat << 3) & 0xf8;
dest_r |= (dest_r >> 5);
dest_g |= (dest_g >> 6);
dest_b |= (dest_b >> 5);
dest_a = 0xff;
ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]);
}
if (params->fbzMode & FBZ_RGB_WMASK)
*(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y);
if (params->fbzMode & FBZ_DEPTH_WMASK)
*(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth;
skip_pixel:
write_addr += 2;
write_addr_aux += 2;
}
}
else
{
int c;
for (c = 0; c < count; c++)
{
if (write_mask & LFB_WRITE_COLOUR)
*(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y);
if (write_mask & LFB_WRITE_DEPTH)
*(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c];
write_addr += 2;
write_addr_aux += 2;
}
}
}

4
pcem/vid_voodoo_fb.h Normal file
View File

@ -0,0 +1,4 @@
uint16_t voodoo_fb_readw(uint32_t addr, void *p);
uint32_t voodoo_fb_readl(uint32_t addr, void *p);
void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p);
void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p);

503
pcem/vid_voodoo_fifo.cpp Normal file
View File

@ -0,0 +1,503 @@
#include <math.h>
#include <stddef.h>
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_banshee_blitter.h"
#include "vid_voodoo_fb.h"
#include "vid_voodoo_fifo.h"
#include "vid_voodoo_reg.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
#include "vid_voodoo_texture.h"
#define WAKE_DELAY (TIMER_USEC * 100)
void voodoo_wake_fifo_thread(voodoo_t *voodoo)
{
if (!timer_is_enabled(&voodoo->wake_timer))
{
/*Don't wake FIFO thread immediately - if we do that it will probably
process one word and go back to sleep, requiring it to be woken on
almost every write. Instead, wait a short while so that the CPU
emulation writes more data so we have more batched-up work.*/
timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY);
}
}
void voodoo_wake_fifo_thread_now(voodoo_t *voodoo)
{
thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
}
void voodoo_wake_timer(void *p)
{
voodoo_t *voodoo = (voodoo_t *)p;
thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
}
void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val)
{
fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK];
while (FIFO_FULL)
{
thread_reset_event(voodoo->fifo_not_full_event);
if (FIFO_FULL)
{
thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/
if (FIFO_FULL)
voodoo_wake_fifo_thread_now(voodoo);
}
}
fifo->val = val;
fifo->addr_type = addr_type;
voodoo->fifo_write_idx++;
if (FIFO_ENTRIES > 0xe000)
voodoo_wake_fifo_thread(voodoo);
}
void voodoo_flush(voodoo_t *voodoo)
{
voodoo->flush = 1;
while (!FIFO_EMPTY)
{
voodoo_wake_fifo_thread_now(voodoo);
thread_wait_event(voodoo->fifo_not_full_event, 1);
}
voodoo_wait_for_render_thread_idle(voodoo);
voodoo->flush = 0;
}
void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo)
{
voodoo_wake_fifo_thread(voodoo);
if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo)
voodoo_wake_fifo_thread(set->voodoos[1]);
}
void voodoo_wait_for_swap_complete(voodoo_t *voodoo)
{
while (voodoo->swap_pending)
{
thread_wait_event(voodoo->wake_fifo_thread, -1);
thread_reset_event(voodoo->wake_fifo_thread);
thread_lock_mutex(voodoo->swap_mutex);
if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL)
{
/*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/
memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line));
voodoo->front_offset = voodoo->params.front_offset;
if (voodoo->swap_count > 0)
voodoo->swap_count--;
voodoo->swap_pending = 0;
thread_unlock_mutex(voodoo->swap_mutex);
break;
}
else
thread_unlock_mutex(voodoo->swap_mutex);
}
}
static uint32_t cmdfifo_get(voodoo_t *voodoo)
{
uint32_t val;
if (!voodoo->cmdfifo_in_sub)
{
while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr)
{
thread_wait_event(voodoo->wake_fifo_thread, -1);
thread_reset_event(voodoo->wake_fifo_thread);
}
}
val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask];
if (!voodoo->cmdfifo_in_sub)
voodoo->cmdfifo_depth_rd++;
voodoo->cmdfifo_rp += 4;
// pclog(" CMDFIFO get %08x\n", val);
return val;
}
static inline float cmdfifo_get_f(voodoo_t *voodoo)
{
union
{
uint32_t i;
float f;
} tempif;
tempif.i = cmdfifo_get(voodoo);
return tempif.f;
}
enum
{
CMDFIFO3_PC_MASK_RGB = (1 << 10),
CMDFIFO3_PC_MASK_ALPHA = (1 << 11),
CMDFIFO3_PC_MASK_Z = (1 << 12),
CMDFIFO3_PC_MASK_Wb = (1 << 13),
CMDFIFO3_PC_MASK_W0 = (1 << 14),
CMDFIFO3_PC_MASK_S0_T0 = (1 << 15),
CMDFIFO3_PC_MASK_W1 = (1 << 16),
CMDFIFO3_PC_MASK_S1_T1 = (1 << 17),
CMDFIFO3_PC = (1 << 28)
};
void voodoo_fifo_thread(void *param)
{
voodoo_t *voodoo = (voodoo_t *)param;
while (1)
{
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)
{
uint64_t start_time = timer_read();
uint64_t end_time;
fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
switch (fifo->addr_type & FIFO_TYPE)
{
case FIFO_WRITEL_REG:
while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_REG)
{
voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
fifo->addr_type = FIFO_INVALID;
voodoo->fifo_read_idx++;
if (FIFO_EMPTY)
break;
fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
}
break;
case FIFO_WRITEW_FB:
voodoo_wait_for_render_thread_idle(voodoo);
while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEW_FB)
{
voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
fifo->addr_type = FIFO_INVALID;
voodoo->fifo_read_idx++;
if (FIFO_EMPTY)
break;
fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
}
break;
case FIFO_WRITEL_FB:
voodoo_wait_for_render_thread_idle(voodoo);
while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_FB)
{
voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
fifo->addr_type = FIFO_INVALID;
voodoo->fifo_read_idx++;
if (FIFO_EMPTY)
break;
fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
}
break;
case FIFO_WRITEL_TEX:
while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_TEX)
{
if (!(fifo->addr_type & 0x400000))
voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
fifo->addr_type = FIFO_INVALID;
voodoo->fifo_read_idx++;
if (FIFO_EMPTY)
break;
fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
}
break;
case FIFO_WRITEL_2DREG:
while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_2DREG)
{
voodoo_2d_reg_writel(voodoo, fifo->addr_type & FIFO_ADDR, fifo->val);
fifo->addr_type = FIFO_INVALID;
voodoo->fifo_read_idx++;
if (FIFO_EMPTY)
break;
fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK];
}
break;
default:
fatal("Unknown fifo entry %08x\n", fifo->addr_type);
}
if (FIFO_ENTRIES > 0xe000)
thread_set_event(voodoo->fifo_not_full_event);
end_time = timer_read();
voodoo->time += end_time - start_time;
}
while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub))
{
uint64_t start_time = timer_read();
uint64_t end_time;
uint32_t header = cmdfifo_get(voodoo);
uint32_t addr;
uint32_t mask;
int smode;
int num;
int num_verticies;
int v_num;
// pclog(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp);
switch (header & 7)
{
case 0:
// pclog("CMDFIFO0\n");
switch ((header >> 3) & 7)
{
case 0: /*NOP*/
break;
case 1: /*JSR*/
// pclog("JSR %08x\n", (header >> 4) & 0xfffffc);
voodoo->cmdfifo_ret_addr = voodoo->cmdfifo_rp;
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_in_sub = 1;
break;
case 2: /*RET*/
voodoo->cmdfifo_rp = voodoo->cmdfifo_ret_addr;
voodoo->cmdfifo_in_sub = 0;
break;
case 3: /*JMP local frame buffer*/
voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc;
// pclog("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header);
break;
default:
fatal("Bad CMDFIFO0 %08x\n", header);
}
break;
case 1:
num = header >> 16;
addr = (header & 0x7ff8) >> 1;
// pclog("CMDFIFO1 addr=%08x\n",addr);
while (num--)
{
uint32_t val = cmdfifo_get(voodoo);
if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE)
{
// if (voodoo->type != VOODOO_BANSHEE)
// fatal("CMDFIFO1: Not Banshee\n");
// pclog("CMDFIFO1: write %08x %08x\n", addr, val);
voodoo_2d_reg_writel(voodoo, addr, val);
}
else
{
if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD ||
(addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
voodoo->cmd_written_fifo++;
if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD)
voodoo->cmd_written_fifo++;
voodoo_reg_writel(addr, val, voodoo);
}
if (header & (1 << 15))
addr += 4;
}
break;
case 2:
if (voodoo->type < VOODOO_BANSHEE)
fatal("CMDFIFO2: Not Banshee\n");
mask = (header >> 3);
addr = 8;
while (mask)
{
if (mask & 1)
{
uint32_t val = cmdfifo_get(voodoo);
voodoo_2d_reg_writel(voodoo, addr, val);
}
addr += 4;
mask >>= 1;
}
break;
case 3:
num = (header >> 29) & 7;
mask = header;//(header >> 10) & 0xff;
smode = (header >> 22) & 0xf;
voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo);
num_verticies = (header >> 6) & 0xf;
v_num = 0;
if (((header >> 3) & 7) == 2)
v_num = 1;
// pclog("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff);
// pclog("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7);
while (num_verticies--)
{
voodoo->verts[3].sVx = cmdfifo_get_f(voodoo);
voodoo->verts[3].sVy = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_RGB)
{
if (header & CMDFIFO3_PC)
{
uint32_t val = cmdfifo_get(voodoo);
voodoo->verts[3].sBlue = (float)(val & 0xff);
voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff);
voodoo->verts[3].sRed = (float)((val >> 16) & 0xff);
voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff);
}
else
{
voodoo->verts[3].sRed = cmdfifo_get_f(voodoo);
voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo);
voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo);
}
}
if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC))
voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_Z)
voodoo->verts[3].sVz = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_Wb)
voodoo->verts[3].sWb = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_W0)
voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_S0_T0)
{
voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo);
voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo);
}
if (mask & CMDFIFO3_PC_MASK_W1)
voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo);
if (mask & CMDFIFO3_PC_MASK_S1_T1)
{
voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo);
voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo);
}
if (v_num)
voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo);
else
voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo);
v_num++;
if (v_num == 3 && ((header >> 3) & 7) == 0)
v_num = 0;
}
break;
case 4:
num = (header >> 29) & 7;
mask = (header >> 15) & 0x3fff;
addr = (header & 0x7ff8) >> 1;
// pclog("CMDFIFO4 addr=%08x\n",addr);
while (mask)
{
if (mask & 1)
{
uint32_t val = cmdfifo_get(voodoo);
if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE)
{
if (voodoo->type < VOODOO_BANSHEE)
fatal("CMDFIFO1: Not Banshee\n");
// pclog("CMDFIFO1: write %08x %08x\n", addr, val);
voodoo_2d_reg_writel(voodoo, addr, val);
}
else
{
if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD ||
(addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
voodoo->cmd_written_fifo++;
if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD)
voodoo->cmd_written_fifo++;
voodoo_reg_writel(addr, val, voodoo);
}
}
addr += 4;
mask >>= 1;
}
while (num--)
cmdfifo_get(voodoo);
break;
case 5:
// if (header & 0x3fc00000)
// fatal("CMDFIFO packet 5 has byte disables set %08x\n", header);
num = (header >> 3) & 0x7ffff;
addr = cmdfifo_get(voodoo) & 0xffffff;
if (!num)
num = 1;
// pclog("CMDFIFO5 addr=%08x num=%i\n", addr, num);
switch (header >> 30)
{
case 0: /*Linear framebuffer (Banshee)*/
if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT])
{
// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0);
}
if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT])
{
// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1);
}
while (num--)
{
uint32_t val = cmdfifo_get(voodoo);
if (addr <= voodoo->fb_mask)
*(uint32_t *)&voodoo->fb_mem[addr] = val;
addr += 4;
}
break;
case 2: /*Framebuffer*/
while (num--)
{
uint32_t val = cmdfifo_get(voodoo);
voodoo_fb_writel(addr, val, voodoo);
addr += 4;
}
break;
case 3: /*Texture*/
while (num--)
{
uint32_t val = cmdfifo_get(voodoo);
voodoo_tex_writel(addr, val, voodoo);
addr += 4;
}
break;
default:
fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp);
}
break;
default:
fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp);
}
end_time = timer_read();
voodoo->time += end_time - start_time;
}
voodoo->voodoo_busy = 0;
}
}

8
pcem/vid_voodoo_fifo.h Normal file
View File

@ -0,0 +1,8 @@
void voodoo_wake_fifo_thread(voodoo_t *voodoo);
void voodoo_wake_fifo_thread_now(voodoo_t *voodoo);
void voodoo_wake_timer(void *p);
void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val);
void voodoo_flush(voodoo_t *voodoo);
void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo);
void voodoo_wait_for_swap_complete(voodoo_t *voodoo);
void voodoo_fifo_thread(void *param);

1321
pcem/vid_voodoo_reg.cpp Normal file

File diff suppressed because it is too large Load Diff

1
pcem/vid_voodoo_reg.h Normal file
View File

@ -0,0 +1 @@
void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p);

691
pcem/vid_voodoo_regs.h Normal file
View File

@ -0,0 +1,691 @@
enum
{
SST_status = 0x000,
SST_intrCtrl = 0x004,
SST_vertexAx = 0x008,
SST_vertexAy = 0x00c,
SST_vertexBx = 0x010,
SST_vertexBy = 0x014,
SST_vertexCx = 0x018,
SST_vertexCy = 0x01c,
SST_startR = 0x0020,
SST_startG = 0x0024,
SST_startB = 0x0028,
SST_startZ = 0x002c,
SST_startA = 0x0030,
SST_startS = 0x0034,
SST_startT = 0x0038,
SST_startW = 0x003c,
SST_dRdX = 0x0040,
SST_dGdX = 0x0044,
SST_dBdX = 0x0048,
SST_dZdX = 0x004c,
SST_dAdX = 0x0050,
SST_dSdX = 0x0054,
SST_dTdX = 0x0058,
SST_dWdX = 0x005c,
SST_dRdY = 0x0060,
SST_dGdY = 0x0064,
SST_dBdY = 0x0068,
SST_dZdY = 0x006c,
SST_dAdY = 0x0070,
SST_dSdY = 0x0074,
SST_dTdY = 0x0078,
SST_dWdY = 0x007c,
SST_triangleCMD = 0x0080,
SST_fvertexAx = 0x088,
SST_fvertexAy = 0x08c,
SST_fvertexBx = 0x090,
SST_fvertexBy = 0x094,
SST_fvertexCx = 0x098,
SST_fvertexCy = 0x09c,
SST_fstartR = 0x00a0,
SST_fstartG = 0x00a4,
SST_fstartB = 0x00a8,
SST_fstartZ = 0x00ac,
SST_fstartA = 0x00b0,
SST_fstartS = 0x00b4,
SST_fstartT = 0x00b8,
SST_fstartW = 0x00bc,
SST_fdRdX = 0x00c0,
SST_fdGdX = 0x00c4,
SST_fdBdX = 0x00c8,
SST_fdZdX = 0x00cc,
SST_fdAdX = 0x00d0,
SST_fdSdX = 0x00d4,
SST_fdTdX = 0x00d8,
SST_fdWdX = 0x00dc,
SST_fdRdY = 0x00e0,
SST_fdGdY = 0x00e4,
SST_fdBdY = 0x00e8,
SST_fdZdY = 0x00ec,
SST_fdAdY = 0x00f0,
SST_fdSdY = 0x00f4,
SST_fdTdY = 0x00f8,
SST_fdWdY = 0x00fc,
SST_ftriangleCMD = 0x0100,
SST_fbzColorPath = 0x104,
SST_fogMode = 0x108,
SST_alphaMode = 0x10c,
SST_fbzMode = 0x110,
SST_lfbMode = 0x114,
SST_clipLeftRight = 0x118,
SST_clipLowYHighY = 0x11c,
SST_nopCMD = 0x120,
SST_fastfillCMD = 0x124,
SST_swapbufferCMD = 0x128,
SST_fogColor = 0x12c,
SST_zaColor = 0x130,
SST_chromaKey = 0x134,
SST_userIntrCMD = 0x13c,
SST_stipple = 0x140,
SST_color0 = 0x144,
SST_color1 = 0x148,
SST_fbiPixelsIn = 0x14c,
SST_fbiChromaFail = 0x150,
SST_fbiZFuncFail = 0x154,
SST_fbiAFuncFail = 0x158,
SST_fbiPixelsOut = 0x15c,
SST_fogTable00 = 0x160,
SST_fogTable01 = 0x164,
SST_fogTable02 = 0x168,
SST_fogTable03 = 0x16c,
SST_fogTable04 = 0x170,
SST_fogTable05 = 0x174,
SST_fogTable06 = 0x178,
SST_fogTable07 = 0x17c,
SST_fogTable08 = 0x180,
SST_fogTable09 = 0x184,
SST_fogTable0a = 0x188,
SST_fogTable0b = 0x18c,
SST_fogTable0c = 0x190,
SST_fogTable0d = 0x194,
SST_fogTable0e = 0x198,
SST_fogTable0f = 0x19c,
SST_fogTable10 = 0x1a0,
SST_fogTable11 = 0x1a4,
SST_fogTable12 = 0x1a8,
SST_fogTable13 = 0x1ac,
SST_fogTable14 = 0x1b0,
SST_fogTable15 = 0x1b4,
SST_fogTable16 = 0x1b8,
SST_fogTable17 = 0x1bc,
SST_fogTable18 = 0x1c0,
SST_fogTable19 = 0x1c4,
SST_fogTable1a = 0x1c8,
SST_fogTable1b = 0x1cc,
SST_fogTable1c = 0x1d0,
SST_fogTable1d = 0x1d4,
SST_fogTable1e = 0x1d8,
SST_fogTable1f = 0x1dc,
SST_cmdFifoBaseAddr = 0x1e0,
SST_cmdFifoBump = 0x1e4,
SST_cmdFifoRdPtr = 0x1e8,
SST_cmdFifoAMin = 0x1ec,
SST_cmdFifoAMax = 0x1f0,
SST_cmdFifoDepth = 0x1f4,
SST_cmdFifoHoles = 0x1f8,
SST_colBufferAddr = 0x1ec, /*Banshee*/
SST_colBufferStride = 0x1f0, /*Banshee*/
SST_auxBufferAddr = 0x1f4, /*Banshee*/
SST_auxBufferStride = 0x1f8, /*Banshee*/
SST_clipLeftRight1 = 0x200, /*Banshee*/
SST_clipTopBottom1 = 0x204, /*Banshee*/
SST_fbiInit4 = 0x200,
SST_vRetrace = 0x204,
SST_backPorch = 0x208,
SST_videoDimensions = 0x20c,
SST_fbiInit0 = 0x210,
SST_fbiInit1 = 0x214,
SST_fbiInit2 = 0x218,
SST_fbiInit3 = 0x21c,
SST_hSync = 0x220,
SST_vSync = 0x224,
SST_clutData = 0x228,
SST_dacData = 0x22c,
SST_scrFilter = 0x230,
SST_hvRetrace = 0x240,
SST_fbiInit5 = 0x244,
SST_fbiInit6 = 0x248,
SST_fbiInit7 = 0x24c,
SST_swapPending = 0x24c, /*Banshee*/
SST_leftOverlayBuf = 0x250, /*Banshee*/
SST_sSetupMode = 0x260,
SST_sVx = 0x264,
SST_sVy = 0x268,
SST_sARGB = 0x26c,
SST_sRed = 0x270,
SST_sGreen = 0x274,
SST_sBlue = 0x278,
SST_sAlpha = 0x27c,
SST_sVz = 0x280,
SST_sWb = 0x284,
SST_sW0 = 0x288,
SST_sS0 = 0x28c,
SST_sT0 = 0x290,
SST_sW1 = 0x294,
SST_sS1 = 0x298,
SST_sT1 = 0x29c,
SST_sDrawTriCMD = 0x2a0,
SST_sBeginTriCMD = 0x2a4,
SST_bltSrcBaseAddr = 0x2c0,
SST_bltDstBaseAddr = 0x2c4,
SST_bltXYStrides = 0x2c8,
SST_bltSrcChromaRange = 0x2cc,
SST_bltDstChromaRange = 0x2d0,
SST_bltClipX = 0x2d4,
SST_bltClipY = 0x2d8,
SST_bltSrcXY = 0x2e0,
SST_bltDstXY = 0x2e4,
SST_bltSize = 0x2e8,
SST_bltRop = 0x2ec,
SST_bltColor = 0x2f0,
SST_bltCommand = 0x2f8,
SST_bltData = 0x2fc,
SST_textureMode = 0x300,
SST_tLOD = 0x304,
SST_tDetail = 0x308,
SST_texBaseAddr = 0x30c,
SST_texBaseAddr1 = 0x310,
SST_texBaseAddr2 = 0x314,
SST_texBaseAddr38 = 0x318,
SST_trexInit1 = 0x320,
SST_nccTable0_Y0 = 0x324,
SST_nccTable0_Y1 = 0x328,
SST_nccTable0_Y2 = 0x32c,
SST_nccTable0_Y3 = 0x330,
SST_nccTable0_I0 = 0x334,
SST_nccTable0_I1 = 0x338,
SST_nccTable0_I2 = 0x33c,
SST_nccTable0_I3 = 0x340,
SST_nccTable0_Q0 = 0x344,
SST_nccTable0_Q1 = 0x348,
SST_nccTable0_Q2 = 0x34c,
SST_nccTable0_Q3 = 0x350,
SST_nccTable1_Y0 = 0x354,
SST_nccTable1_Y1 = 0x358,
SST_nccTable1_Y2 = 0x35c,
SST_nccTable1_Y3 = 0x360,
SST_nccTable1_I0 = 0x364,
SST_nccTable1_I1 = 0x368,
SST_nccTable1_I2 = 0x36c,
SST_nccTable1_I3 = 0x370,
SST_nccTable1_Q0 = 0x374,
SST_nccTable1_Q1 = 0x378,
SST_nccTable1_Q2 = 0x37c,
SST_nccTable1_Q3 = 0x380,
SST_remap_status = 0x000 | 0x400,
SST_remap_vertexAx = 0x008 | 0x400,
SST_remap_vertexAy = 0x00c | 0x400,
SST_remap_vertexBx = 0x010 | 0x400,
SST_remap_vertexBy = 0x014 | 0x400,
SST_remap_vertexCx = 0x018 | 0x400,
SST_remap_vertexCy = 0x01c | 0x400,
SST_remap_startR = 0x0020 | 0x400,
SST_remap_startG = 0x002c | 0x400,
SST_remap_startB = 0x0038 | 0x400,
SST_remap_startZ = 0x0044 | 0x400,
SST_remap_startA = 0x0050 | 0x400,
SST_remap_startS = 0x005c | 0x400,
SST_remap_startT = 0x0068 | 0x400,
SST_remap_startW = 0x0074 | 0x400,
SST_remap_dRdX = 0x0024 | 0x400,
SST_remap_dGdX = 0x0030 | 0x400,
SST_remap_dBdX = 0x003c | 0x400,
SST_remap_dZdX = 0x0048 | 0x400,
SST_remap_dAdX = 0x0054 | 0x400,
SST_remap_dSdX = 0x0060 | 0x400,
SST_remap_dTdX = 0x006c | 0x400,
SST_remap_dWdX = 0x0078 | 0x400,
SST_remap_dRdY = 0x0028 | 0x400,
SST_remap_dGdY = 0x0034 | 0x400,
SST_remap_dBdY = 0x0040 | 0x400,
SST_remap_dZdY = 0x004c | 0x400,
SST_remap_dAdY = 0x0058 | 0x400,
SST_remap_dSdY = 0x0064 | 0x400,
SST_remap_dTdY = 0x0070 | 0x400,
SST_remap_dWdY = 0x007c | 0x400,
SST_remap_triangleCMD = 0x0080 | 0x400,
SST_remap_fvertexAx = 0x088 | 0x400,
SST_remap_fvertexAy = 0x08c | 0x400,
SST_remap_fvertexBx = 0x090 | 0x400,
SST_remap_fvertexBy = 0x094 | 0x400,
SST_remap_fvertexCx = 0x098 | 0x400,
SST_remap_fvertexCy = 0x09c | 0x400,
SST_remap_fstartR = 0x00a0 | 0x400,
SST_remap_fstartG = 0x00ac | 0x400,
SST_remap_fstartB = 0x00b8 | 0x400,
SST_remap_fstartZ = 0x00c4 | 0x400,
SST_remap_fstartA = 0x00d0 | 0x400,
SST_remap_fstartS = 0x00dc | 0x400,
SST_remap_fstartT = 0x00e8 | 0x400,
SST_remap_fstartW = 0x00f4 | 0x400,
SST_remap_fdRdX = 0x00a4 | 0x400,
SST_remap_fdGdX = 0x00b0 | 0x400,
SST_remap_fdBdX = 0x00bc | 0x400,
SST_remap_fdZdX = 0x00c8 | 0x400,
SST_remap_fdAdX = 0x00d4 | 0x400,
SST_remap_fdSdX = 0x00e0 | 0x400,
SST_remap_fdTdX = 0x00ec | 0x400,
SST_remap_fdWdX = 0x00f8 | 0x400,
SST_remap_fdRdY = 0x00a8 | 0x400,
SST_remap_fdGdY = 0x00b4 | 0x400,
SST_remap_fdBdY = 0x00c0 | 0x400,
SST_remap_fdZdY = 0x00cc | 0x400,
SST_remap_fdAdY = 0x00d8 | 0x400,
SST_remap_fdSdY = 0x00e4 | 0x400,
SST_remap_fdTdY = 0x00f0 | 0x400,
SST_remap_fdWdY = 0x00fc | 0x400,
};
enum
{
LFB_WRITE_FRONT = 0x0000,
LFB_WRITE_BACK = 0x0010,
LFB_WRITE_MASK = 0x0030
};
enum
{
LFB_READ_FRONT = 0x0000,
LFB_READ_BACK = 0x0040,
LFB_READ_AUX = 0x0080,
LFB_READ_MASK = 0x00c0
};
enum
{
LFB_FORMAT_RGB565 = 0,
LFB_FORMAT_RGB555 = 1,
LFB_FORMAT_ARGB1555 = 2,
LFB_FORMAT_ARGB8888 = 5,
LFB_FORMAT_DEPTH = 15,
LFB_FORMAT_MASK = 15
};
enum
{
LFB_WRITE_COLOUR = 1,
LFB_WRITE_DEPTH = 2
};
enum
{
FBZ_CHROMAKEY = (1 << 1),
FBZ_W_BUFFER = (1 << 3),
FBZ_DEPTH_ENABLE = (1 << 4),
FBZ_DITHER = (1 << 8),
FBZ_RGB_WMASK = (1 << 9),
FBZ_DEPTH_WMASK = (1 << 10),
FBZ_DITHER_2x2 = (1 << 11),
FBZ_DRAW_FRONT = 0x0000,
FBZ_DRAW_BACK = 0x4000,
FBZ_DRAW_MASK = 0xc000,
FBZ_DEPTH_BIAS = (1 << 16),
FBZ_DEPTH_SOURCE = (1 << 20),
FBZ_PARAM_ADJUST = (1 << 26)
};
enum
{
TEX_RGB332 = 0x0,
TEX_Y4I2Q2 = 0x1,
TEX_A8 = 0x2,
TEX_I8 = 0x3,
TEX_AI8 = 0x4,
TEX_PAL8 = 0x5,
TEX_APAL8 = 0x6,
TEX_ARGB8332 = 0x8,
TEX_A8Y4I2Q2 = 0x9,
TEX_R5G6B5 = 0xa,
TEX_ARGB1555 = 0xb,
TEX_ARGB4444 = 0xc,
TEX_A8I8 = 0xd,
TEX_APAL88 = 0xe
};
enum
{
TEXTUREMODE_NCC_SEL = (1 << 5),
TEXTUREMODE_TCLAMPS = (1 << 6),
TEXTUREMODE_TCLAMPT = (1 << 7),
TEXTUREMODE_TRILINEAR = (1 << 30)
};
enum
{
FBIINIT0_VGA_PASS = 1,
FBIINIT0_GRAPHICS_RESET = (1 << 1)
};
enum
{
FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/
FBIINIT1_VIDEO_RESET = (1 << 8),
FBIINIT1_SLI_ENABLE = (1 << 23)
};
enum
{
FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9)
};
enum
{
FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9),
FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9),
FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9),
FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9)
};
enum
{
FBIINIT3_REMAP = 1
};
enum
{
FBIINIT5_MULTI_CVG = (1 << 14)
};
enum
{
FBIINIT7_CMDFIFO_ENABLE = (1 << 8)
};
enum
{
CC_LOCALSELECT_ITER_RGB = 0,
CC_LOCALSELECT_TEX = 1,
CC_LOCALSELECT_COLOR1 = 2,
CC_LOCALSELECT_LFB = 3
};
enum
{
CCA_LOCALSELECT_ITER_A = 0,
CCA_LOCALSELECT_COLOR0 = 1,
CCA_LOCALSELECT_ITER_Z = 2
};
enum
{
C_SEL_ITER_RGB = 0,
C_SEL_TEX = 1,
C_SEL_COLOR1 = 2,
C_SEL_LFB = 3
};
enum
{
A_SEL_ITER_A = 0,
A_SEL_TEX = 1,
A_SEL_COLOR1 = 2,
A_SEL_LFB = 3
};
enum
{
CC_MSELECT_ZERO = 0,
CC_MSELECT_CLOCAL = 1,
CC_MSELECT_AOTHER = 2,
CC_MSELECT_ALOCAL = 3,
CC_MSELECT_TEX = 4,
CC_MSELECT_TEXRGB = 5
};
enum
{
CCA_MSELECT_ZERO = 0,
CCA_MSELECT_ALOCAL = 1,
CCA_MSELECT_AOTHER = 2,
CCA_MSELECT_ALOCAL2 = 3,
CCA_MSELECT_TEX = 4
};
enum
{
TC_MSELECT_ZERO = 0,
TC_MSELECT_CLOCAL = 1,
TC_MSELECT_AOTHER = 2,
TC_MSELECT_ALOCAL = 3,
TC_MSELECT_DETAIL = 4,
TC_MSELECT_LOD_FRAC = 5
};
enum
{
TCA_MSELECT_ZERO = 0,
TCA_MSELECT_CLOCAL = 1,
TCA_MSELECT_AOTHER = 2,
TCA_MSELECT_ALOCAL = 3,
TCA_MSELECT_DETAIL = 4,
TCA_MSELECT_LOD_FRAC = 5
};
enum
{
CC_ADD_CLOCAL = 1,
CC_ADD_ALOCAL = 2
};
enum
{
CCA_ADD_CLOCAL = 1,
CCA_ADD_ALOCAL = 2
};
enum
{
AFUNC_AZERO = 0x0,
AFUNC_ASRC_ALPHA = 0x1,
AFUNC_A_COLOR = 0x2,
AFUNC_ADST_ALPHA = 0x3,
AFUNC_AONE = 0x4,
AFUNC_AOMSRC_ALPHA = 0x5,
AFUNC_AOM_COLOR = 0x6,
AFUNC_AOMDST_ALPHA = 0x7,
AFUNC_ASATURATE = 0xf
};
enum
{
AFUNC_ACOLORBEFOREFOG = 0xf
};
enum
{
AFUNC_NEVER = 0,
AFUNC_LESSTHAN = 1,
AFUNC_EQUAL = 2,
AFUNC_LESSTHANEQUAL = 3,
AFUNC_GREATERTHAN = 4,
AFUNC_NOTEQUAL = 5,
AFUNC_GREATERTHANEQUAL = 6,
AFUNC_ALWAYS = 7
};
enum
{
DEPTHOP_NEVER = 0,
DEPTHOP_LESSTHAN = 1,
DEPTHOP_EQUAL = 2,
DEPTHOP_LESSTHANEQUAL = 3,
DEPTHOP_GREATERTHAN = 4,
DEPTHOP_NOTEQUAL = 5,
DEPTHOP_GREATERTHANEQUAL = 6,
DEPTHOP_ALWAYS = 7
};
enum
{
FOG_ENABLE = 0x01,
FOG_ADD = 0x02,
FOG_MULT = 0x04,
FOG_ALPHA = 0x08,
FOG_Z = 0x10,
FOG_W = 0x18,
FOG_CONSTANT = 0x20
};
enum
{
LOD_ODD = (1 << 18),
LOD_SPLIT = (1 << 19),
LOD_S_IS_WIDER = (1 << 20),
LOD_TMULTIBASEADDR = (1 << 24),
LOD_TMIRROR_S = (1 << 28),
LOD_TMIRROR_T = (1 << 29)
};
enum
{
CMD_INVALID = 0,
CMD_DRAWTRIANGLE,
CMD_FASTFILL,
CMD_SWAPBUF
};
enum
{
FBZCP_TEXTURE_ENABLED = (1 << 27)
};
enum
{
BLTCMD_SRC_TILED = (1 << 14),
BLTCMD_DST_TILED = (1 << 15)
};
enum
{
INITENABLE_SLI_MASTER_SLAVE = (1 << 11)
};
enum
{
SETUPMODE_RGB = (1 << 0),
SETUPMODE_ALPHA = (1 << 1),
SETUPMODE_Z = (1 << 2),
SETUPMODE_Wb = (1 << 3),
SETUPMODE_W0 = (1 << 4),
SETUPMODE_S0_T0 = (1 << 5),
SETUPMODE_W1 = (1 << 6),
SETUPMODE_S1_T1 = (1 << 7),
SETUPMODE_STRIP_MODE = (1 << 16),
SETUPMODE_CULLING_ENABLE = (1 << 17),
SETUPMODE_CULLING_SIGN = (1 << 18),
SETUPMODE_DISABLE_PINGPONG = (1 << 19)
};
#define TEXTUREMODE_MASK 0x3ffff000
#define TEXTUREMODE_PASSTHROUGH 0
#define TEXTUREMODE_LOCAL_MASK 0x00643000
#define TEXTUREMODE_LOCAL 0x00241000
#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE)
#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400)
#define _rgb_sel ( params->fbzColorPath & 3)
#define a_sel ( (params->fbzColorPath >> 2) & 3)
#define cc_localselect ( params->fbzColorPath & (1 << 4))
#define cca_localselect ( (params->fbzColorPath >> 5) & 3)
#define cc_localselect_override ( params->fbzColorPath & (1 << 7))
#define cc_zero_other ( params->fbzColorPath & (1 << 8))
#define cc_sub_clocal ( params->fbzColorPath & (1 << 9))
#define cc_mselect ( (params->fbzColorPath >> 10) & 7)
#define cc_reverse_blend ( params->fbzColorPath & (1 << 13))
#define cc_add ( (params->fbzColorPath >> 14) & 3)
#define cc_add_alocal ( params->fbzColorPath & (1 << 15))
#define cc_invert_output ( params->fbzColorPath & (1 << 16))
#define cca_zero_other ( params->fbzColorPath & (1 << 17))
#define cca_sub_clocal ( params->fbzColorPath & (1 << 18))
#define cca_mselect ( (params->fbzColorPath >> 19) & 7)
#define cca_reverse_blend ( params->fbzColorPath & (1 << 22))
#define cca_add ( (params->fbzColorPath >> 23) & 3)
#define cca_invert_output ( params->fbzColorPath & (1 << 25))
#define tc_zero_other (params->textureMode[0] & (1 << 12))
#define tc_sub_clocal (params->textureMode[0] & (1 << 13))
#define tc_mselect ((params->textureMode[0] >> 14) & 7)
#define tc_reverse_blend (params->textureMode[0] & (1 << 17))
#define tc_add_clocal (params->textureMode[0] & (1 << 18))
#define tc_add_alocal (params->textureMode[0] & (1 << 19))
#define tc_invert_output (params->textureMode[0] & (1 << 20))
#define tca_zero_other (params->textureMode[0] & (1 << 21))
#define tca_sub_clocal (params->textureMode[0] & (1 << 22))
#define tca_mselect ((params->textureMode[0] >> 23) & 7)
#define tca_reverse_blend (params->textureMode[0] & (1 << 26))
#define tca_add_clocal (params->textureMode[0] & (1 << 27))
#define tca_add_alocal (params->textureMode[0] & (1 << 28))
#define tca_invert_output (params->textureMode[0] & (1 << 29))
#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13))
#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7)
#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17))
#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18))
#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19))
#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22))
#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7)
#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26))
#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27))
#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28))
#define src_afunc ( (params->alphaMode >> 8) & 0xf)
#define dest_afunc ( (params->alphaMode >> 12) & 0xf)
#define alpha_func ( (params->alphaMode >> 1) & 7)
#define a_ref ( params->alphaMode >> 24)
#define depth_op ( (params->fbzMode >> 5) & 7)
#define dither ( params->fbzMode & FBZ_DITHER)
#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2)

1640
pcem/vid_voodoo_render.cpp Normal file

File diff suppressed because it is too large Load Diff

338
pcem/vid_voodoo_render.h Normal file
View File

@ -0,0 +1,338 @@
#if !(defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32) && !(defined __amd64__)
#define NO_CODEGEN
#endif
#ifndef NO_CODEGEN
void voodoo_codegen_init(voodoo_t *voodoo);
void voodoo_codegen_close(voodoo_t *voodoo);
#endif
#define DEPTH_TEST(comp_depth) \
do \
{ \
switch (depth_op) \
{ \
case DEPTHOP_NEVER: \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
case DEPTHOP_LESSTHAN: \
if (!(comp_depth < old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_EQUAL: \
if (!(comp_depth == old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_LESSTHANEQUAL: \
if (!(comp_depth <= old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_GREATERTHAN: \
if (!(comp_depth > old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_NOTEQUAL: \
if (!(comp_depth != old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_GREATERTHANEQUAL: \
if (!(comp_depth >= old_depth)) \
{ \
voodoo->fbiZFuncFail++; \
goto skip_pixel; \
} \
break; \
case DEPTHOP_ALWAYS: \
break; \
} \
} while (0)
#define APPLY_FOG(src_r, src_g, src_b, z, ia, w) \
do \
{ \
if (params->fogMode & FOG_CONSTANT) \
{ \
src_r += params->fogColor.r; \
src_g += params->fogColor.g; \
src_b += params->fogColor.b; \
} \
else \
{ \
int fog_r, fog_g, fog_b, fog_a = 0; \
int fog_idx; \
\
if (!(params->fogMode & FOG_ADD)) \
{ \
fog_r = params->fogColor.r; \
fog_g = params->fogColor.g; \
fog_b = params->fogColor.b; \
} \
else \
fog_r = fog_g = fog_b = 0; \
\
if (!(params->fogMode & FOG_MULT)) \
{ \
fog_r -= src_r; \
fog_g -= src_g; \
fog_b -= src_b; \
} \
\
switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \
{ \
case 0: \
fog_idx = (w_depth >> 10) & 0x3f; \
\
fog_a = params->fogTable[fog_idx].fog; \
fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \
break; \
case FOG_Z: \
fog_a = (z >> 20) & 0xff; \
break; \
case FOG_ALPHA: \
fog_a = CLAMP(ia >> 12); \
break; \
case FOG_W: \
fog_a = CLAMP((w >> 32) & 0xff); \
break; \
} \
fog_a++; \
\
fog_r = (fog_r * fog_a) >> 8; \
fog_g = (fog_g * fog_a) >> 8; \
fog_b = (fog_b * fog_a) >> 8; \
\
if (params->fogMode & FOG_MULT) \
{ \
src_r = fog_r; \
src_g = fog_g; \
src_b = fog_b; \
} \
else \
{ \
src_r += fog_r; \
src_g += fog_g; \
src_b += fog_b; \
} \
} \
\
src_r = CLAMP(src_r); \
src_g = CLAMP(src_g); \
src_b = CLAMP(src_b); \
} while (0)
#define ALPHA_TEST(src_a) \
do \
{ \
switch (alpha_func) \
{ \
case AFUNC_NEVER: \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
case AFUNC_LESSTHAN: \
if (!(src_a < a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_EQUAL: \
if (!(src_a == a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_LESSTHANEQUAL: \
if (!(src_a <= a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_GREATERTHAN: \
if (!(src_a > a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_NOTEQUAL: \
if (!(src_a != a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_GREATERTHANEQUAL: \
if (!(src_a >= a_ref)) \
{ \
voodoo->fbiAFuncFail++; \
goto skip_pixel; \
} \
break; \
case AFUNC_ALWAYS: \
break; \
} \
} while (0)
#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \
do \
{ \
int _a; \
int newdest_r = 0, newdest_g = 0, newdest_b = 0; \
\
switch (dest_afunc) \
{ \
case AFUNC_AZERO: \
newdest_r = newdest_g = newdest_b = 0; \
break; \
case AFUNC_ASRC_ALPHA: \
newdest_r = (dest_r * src_a) / 255; \
newdest_g = (dest_g * src_a) / 255; \
newdest_b = (dest_b * src_a) / 255; \
break; \
case AFUNC_A_COLOR: \
newdest_r = (dest_r * src_r) / 255; \
newdest_g = (dest_g * src_g) / 255; \
newdest_b = (dest_b * src_b) / 255; \
break; \
case AFUNC_ADST_ALPHA: \
newdest_r = (dest_r * dest_a) / 255; \
newdest_g = (dest_g * dest_a) / 255; \
newdest_b = (dest_b * dest_a) / 255; \
break; \
case AFUNC_AONE: \
newdest_r = dest_r; \
newdest_g = dest_g; \
newdest_b = dest_b; \
break; \
case AFUNC_AOMSRC_ALPHA: \
newdest_r = (dest_r * (255-src_a)) / 255; \
newdest_g = (dest_g * (255-src_a)) / 255; \
newdest_b = (dest_b * (255-src_a)) / 255; \
break; \
case AFUNC_AOM_COLOR: \
newdest_r = (dest_r * (255-src_r)) / 255; \
newdest_g = (dest_g * (255-src_g)) / 255; \
newdest_b = (dest_b * (255-src_b)) / 255; \
break; \
case AFUNC_AOMDST_ALPHA: \
newdest_r = (dest_r * (255-dest_a)) / 255; \
newdest_g = (dest_g * (255-dest_a)) / 255; \
newdest_b = (dest_b * (255-dest_a)) / 255; \
break; \
case AFUNC_ASATURATE: \
_a = MIN(src_a, 1-dest_a); \
newdest_r = (dest_r * _a) / 255; \
newdest_g = (dest_g * _a) / 255; \
newdest_b = (dest_b * _a) / 255; \
break; \
} \
\
switch (src_afunc) \
{ \
case AFUNC_AZERO: \
src_r = src_g = src_b = 0; \
break; \
case AFUNC_ASRC_ALPHA: \
src_r = (src_r * src_a) / 255; \
src_g = (src_g * src_a) / 255; \
src_b = (src_b * src_a) / 255; \
break; \
case AFUNC_A_COLOR: \
src_r = (src_r * dest_r) / 255; \
src_g = (src_g * dest_g) / 255; \
src_b = (src_b * dest_b) / 255; \
break; \
case AFUNC_ADST_ALPHA: \
src_r = (src_r * dest_a) / 255; \
src_g = (src_g * dest_a) / 255; \
src_b = (src_b * dest_a) / 255; \
break; \
case AFUNC_AONE: \
break; \
case AFUNC_AOMSRC_ALPHA: \
src_r = (src_r * (255-src_a)) / 255; \
src_g = (src_g * (255-src_a)) / 255; \
src_b = (src_b * (255-src_a)) / 255; \
break; \
case AFUNC_AOM_COLOR: \
src_r = (src_r * (255-dest_r)) / 255; \
src_g = (src_g * (255-dest_g)) / 255; \
src_b = (src_b * (255-dest_b)) / 255; \
break; \
case AFUNC_AOMDST_ALPHA: \
src_r = (src_r * (255-dest_a)) / 255; \
src_g = (src_g * (255-dest_a)) / 255; \
src_b = (src_b * (255-dest_a)) / 255; \
break; \
case AFUNC_ACOLORBEFOREFOG: \
fatal("AFUNC_ACOLORBEFOREFOG\n"); \
break; \
} \
\
src_r += newdest_r; \
src_g += newdest_g; \
src_b += newdest_b; \
\
src_r = CLAMP(src_r); \
src_g = CLAMP(src_g); \
src_b = CLAMP(src_b); \
} while(0)
void voodoo_render_thread_1(void *param);
void voodoo_render_thread_2(void *param);
void voodoo_render_thread_3(void *param);
void voodoo_render_thread_4(void *param);
void voodoo_queue_triangle(voodoo_t *voodoo, voodoo_params_t *params);
extern int voodoo_recomp;
extern int tris;
static inline void voodoo_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*/
if (voodoo->render_threads == 4)
{
thread_set_event(voodoo->wake_render_thread[2]); /*Wake up render thread if moving from idle*/
thread_set_event(voodoo->wake_render_thread[3]); /*Wake up render thread if moving from idle*/
}
}
static inline void voodoo_wait_for_render_thread_idle(voodoo_t *voodoo)
{
while (!PARAM_EMPTY(0) || (voodoo->render_threads >= 2 && !PARAM_EMPTY(1)) ||
(voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || !PARAM_EMPTY(3))) ||
voodoo->render_voodoo_busy[0] || (voodoo->render_threads >= 2 && voodoo->render_voodoo_busy[1]) ||
(voodoo->render_threads == 4 && (voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3])))
{
voodoo_wake_render_thread(voodoo);
if (!PARAM_EMPTY(0) || voodoo->render_voodoo_busy[0])
thread_wait_event(voodoo->render_not_full_event[0], 1);
if (voodoo->render_threads >= 2 && (!PARAM_EMPTY(1) || voodoo->render_voodoo_busy[1]))
thread_wait_event(voodoo->render_not_full_event[1], 1);
if (voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || voodoo->render_voodoo_busy[2]))
thread_wait_event(voodoo->render_not_full_event[2], 1);
if (voodoo->render_threads == 4 && (!PARAM_EMPTY(3) || voodoo->render_voodoo_busy[3]))
thread_wait_event(voodoo->render_not_full_event[3], 1);
}
}

216
pcem/vid_voodoo_setup.cpp Normal file
View File

@ -0,0 +1,216 @@
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
#include "vid_voodoo_setup.h"
void voodoo_triangle_setup(voodoo_t *voodoo)
{
float dxAB, dxBC, dyAB, dyBC;
float area;
int va = 0, vb = 1, vc = 2;
vert_t verts[3];
verts[0] = voodoo->verts[0];
verts[1] = voodoo->verts[1];
verts[2] = voodoo->verts[2];
if (verts[0].sVy < verts[1].sVy)
{
if (verts[1].sVy < verts[2].sVy)
{
/* V1>V0, V2>V1, V2>V1>V0*/
va = 0; /*OK*/
vb = 1;
vc = 2;
}
else
{
/* V1>V0, V1>V2*/
if (verts[0].sVy < verts[2].sVy)
{
/* V1>V0, V1>V2, V2>V0, V1>V2>V0*/
va = 0;
vb = 2;
vc = 1;
}
else
{
/* V1>V0, V1>V2, V0>V2, V1>V0>V2*/
va = 2;
vb = 0;
vc = 1;
}
}
}
else
{
if (verts[1].sVy < verts[2].sVy)
{
/* V0>V1, V2>V1*/
if (verts[0].sVy < verts[2].sVy)
{
/* V0>V1, V2>V1, V2>V0, V2>V0>V1*/
va = 1;
vb = 0;
vc = 2;
}
else
{
/* V0>V1, V2>V1, V0>V2, V0>V2>V1*/
va = 1;
vb = 2;
vc = 0;
}
}
else
{
/*V0>V1>V2*/
va = 2;
vb = 1;
vc = 0;
}
}
dxAB = verts[0].sVx - verts[1].sVx;
dxBC = verts[1].sVx - verts[2].sVx;
dyAB = verts[0].sVy - verts[1].sVy;
dyBC = verts[1].sVy - verts[2].sVy;
area = dxAB * dyBC - dxBC * dyAB;
if (area == 0.0)
return;
if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE)
{
int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN;
int sign = (area < 0.0);
if ((voodoo->sSetupMode & (SETUPMODE_CULLING_ENABLE | SETUPMODE_DISABLE_PINGPONG))
== SETUPMODE_CULLING_ENABLE && voodoo->cull_pingpong)
cull_sign = !cull_sign;
if (cull_sign && sign)
return;
if (!cull_sign && !sign)
return;
}
dxAB = verts[va].sVx - verts[vb].sVx;
dxBC = verts[vb].sVx - verts[vc].sVx;
dyAB = verts[va].sVy - verts[vb].sVy;
dyBC = verts[vb].sVy - verts[vc].sVy;
area = dxAB * dyBC - dxBC * dyAB;
dxAB /= area;
dxBC /= area;
dyAB /= area;
dyBC /= area;
voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff);
voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff);
voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(verts[vb].sVx * 16.0f) & 0xffff);
voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(verts[vb].sVy * 16.0f) & 0xffff);
voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff);
voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff);
if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy)
{
pclog("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy);
return;
}
if (voodoo->sSetupMode & SETUPMODE_RGB)
{
voodoo->params.startR = (int32_t)(verts[va].sRed * 4096.0f);
voodoo->params.dRdX = (int32_t)(((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f);
voodoo->params.dRdY = (int32_t)(((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f);
voodoo->params.startG = (int32_t)(verts[va].sGreen * 4096.0f);
voodoo->params.dGdX = (int32_t)(((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f);
voodoo->params.dGdY = (int32_t)(((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f);
voodoo->params.startB = (int32_t)(verts[va].sBlue * 4096.0f);
voodoo->params.dBdX = (int32_t)(((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f);
voodoo->params.dBdY = (int32_t)(((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f);
}
if (voodoo->sSetupMode & SETUPMODE_ALPHA)
{
voodoo->params.startA = (int32_t)(verts[va].sAlpha * 4096.0f);
voodoo->params.dAdX = (int32_t)(((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f);
voodoo->params.dAdY = (int32_t)(((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f);
}
if (voodoo->sSetupMode & SETUPMODE_Z)
{
voodoo->params.startZ = (int32_t)(verts[va].sVz * 4096.0f);
voodoo->params.dZdX = (int32_t)(((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f);
voodoo->params.dZdY = (int32_t)(((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f);
}
if (voodoo->sSetupMode & SETUPMODE_Wb)
{
voodoo->params.startW = (int64_t)(verts[va].sWb * 4294967296.0f);
voodoo->params.dWdX = (int64_t)(((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f);
voodoo->params.dWdY = (int64_t)(((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f);
voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW;
voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX;
voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY;
}
if (voodoo->sSetupMode & SETUPMODE_W0)
{
voodoo->params.tmu[0].startW = (int64_t)(verts[va].sW0 * 4294967296.0f);
voodoo->params.tmu[0].dWdX = (int64_t)(((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f);
voodoo->params.tmu[0].dWdY = (int64_t)(((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f);
voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW;
voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX;
voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY;
}
if (voodoo->sSetupMode & SETUPMODE_S0_T0)
{
voodoo->params.tmu[0].startS = (int64_t)(verts[va].sS0 * 4294967296.0f);
voodoo->params.tmu[0].dSdX = (int64_t)(((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f);
voodoo->params.tmu[0].dSdY = (int64_t)(((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f);
voodoo->params.tmu[0].startT = (int64_t)(verts[va].sT0 * 4294967296.0f);
voodoo->params.tmu[0].dTdX = (int64_t)(((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f);
voodoo->params.tmu[0].dTdY = (int64_t)(((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f);
voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS;
voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX;
voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY;
voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT;
voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX;
voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY;
}
if (voodoo->sSetupMode & SETUPMODE_W1)
{
voodoo->params.tmu[1].startW = (int64_t)(verts[va].sW1 * 4294967296.0f);
voodoo->params.tmu[1].dWdX = (int64_t)(((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f);
voodoo->params.tmu[1].dWdY = (int64_t)(((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f);
}
if (voodoo->sSetupMode & SETUPMODE_S1_T1)
{
voodoo->params.tmu[1].startS = (int64_t)(verts[va].sS1 * 4294967296.0f);
voodoo->params.tmu[1].dSdX = (int64_t)(((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f);
voodoo->params.tmu[1].dSdY = (int64_t)(((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f);
voodoo->params.tmu[1].startT = (int64_t)(verts[va].sT1 * 4294967296.0f);
voodoo->params.tmu[1].dTdX = (int64_t)(((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f);
voodoo->params.tmu[1].dTdY = (int64_t)(((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f);
}
voodoo->params.sign = (area < 0.0);
if (voodoo->ncc_dirty[0])
voodoo_update_ncc(voodoo, 0);
if (voodoo->ncc_dirty[1])
voodoo_update_ncc(voodoo, 1);
voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0;
voodoo_queue_triangle(voodoo, &voodoo->params);
}

1
pcem/vid_voodoo_setup.h Normal file
View File

@ -0,0 +1 @@
void voodoo_triangle_setup(voodoo_t *voodoo);

583
pcem/vid_voodoo_texture.cpp Normal file
View File

@ -0,0 +1,583 @@
#include <math.h>
#include <stddef.h>
#include "ibm.h"
#include "device.h"
#include "mem.h"
#include "thread.h"
#include "video.h"
#include "vid_svga.h"
#include "vid_voodoo.h"
#include "vid_voodoo_common.h"
#include "vid_voodoo_dither.h"
#include "vid_voodoo_regs.h"
#include "vid_voodoo_render.h"
#include "vid_voodoo_texture.h"
void voodoo_recalc_tex(voodoo_t *voodoo, int tmu)
{
int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3;
int width = 256, height = 256;
int shift = 8;
int lod;
uint32_t base = voodoo->params.texBaseAddr[tmu];
uint32_t offset = 0;
int tex_lod = 0;
uint32_t offsets[LOD_MAX+3];
int widths[LOD_MAX+3], heights[LOD_MAX+3], shifts[LOD_MAX+3];
if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER)
height >>= aspect;
else
{
width >>= aspect;
shift -= aspect;
}
for (lod = 0; lod <= LOD_MAX + 2; lod++)
{
offsets[lod] = offset;
widths[lod] = width >> lod;
heights[lod] = height >> lod;
shifts[lod] = shift - lod;
if (!widths[lod])
widths[lod] = 1;
if (!heights[lod])
heights[lod] = 1;
if (shifts[lod] < 0)
shifts[lod] = 0;
if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) ||
((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) ||
(!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD)))
{
if (voodoo->params.tformat[tmu] & 8)
offset += (width >> lod) * (height >> lod) * 2;
else
offset += (width >> lod) * (height >> lod);
}
}
if ((voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) && (voodoo->params.tLOD[tmu] & LOD_ODD))
tex_lod++; /*Skip LOD 0*/
// pclog("TMU %i: %08x\n", tmu, voodoo->params.textureMode[tmu]);
for (lod = 0; lod <= LOD_MAX+1; lod++)
{
if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)
{
switch (tex_lod)
{
case 0:
base = voodoo->params.texBaseAddr[tmu];
break;
case 1:
base = voodoo->params.texBaseAddr1[tmu];
break;
case 2:
base = voodoo->params.texBaseAddr2[tmu];
break;
default:
base = voodoo->params.texBaseAddr38[tmu];
break;
}
}
voodoo->params.tex_base[tmu][lod] = base + offsets[tex_lod];
if (voodoo->params.tformat[tmu] & 8)
voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod] * 2);
else
voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod]);
voodoo->params.tex_w_mask[tmu][lod] = widths[tex_lod] - 1;
voodoo->params.tex_w_nmask[tmu][lod] = ~(widths[tex_lod] - 1);
voodoo->params.tex_h_mask[tmu][lod] = heights[tex_lod] - 1;
voodoo->params.tex_shift[tmu][lod] = shifts[tex_lod];
voodoo->params.tex_lod[tmu][lod] = tex_lod;
if (!(voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) ||
((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) ||
(!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD)))
{
if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0)
{
if (voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR)
tex_lod += 2;
else
tex_lod++;
}
}
}
voodoo->params.tex_width[tmu] = width;
}
#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24))
void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu)
{
int c, d;
int lod;
int lod_min, lod_max;
uint32_t addr = 0, addr_end;
uint32_t palette_checksum;
lod_min = (params->tLOD[tmu] >> 2) & 15;
lod_max = (params->tLOD[tmu] >> 8) & 15;
if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88)
{
if (voodoo->palette_dirty[tmu])
{
palette_checksum = 0;
for (c = 0; c < 256; c++)
palette_checksum ^= voodoo->palette[tmu][c].u;
voodoo->palette_checksum[tmu] = palette_checksum;
voodoo->palette_dirty[tmu] = 0;
}
else
palette_checksum = voodoo->palette_checksum[tmu];
}
else
palette_checksum = 0;
if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR))
addr = params->texBaseAddr1[tmu];
else
addr = params->texBaseAddr[tmu];
/*Try to find texture in cache*/
for (c = 0; c < TEX_CACHE_MAX; c++)
{
if (voodoo->texture_cache[tmu][c].base == addr &&
voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) &&
voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum)
{
params->tex_entry[tmu] = c;
voodoo->texture_cache[tmu][c].refcount++;
return;
}
}
/*Texture not found, search for unused texture*/
do
{
for (c = 0; c < TEX_CACHE_MAX; c++)
{
voodoo->texture_last_removed++;
voodoo->texture_last_removed &= (TEX_CACHE_MAX-1);
if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] &&
(voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1]))
break;
}
if (c == TEX_CACHE_MAX)
voodoo_wait_for_render_thread_idle(voodoo);
} while (c == TEX_CACHE_MAX);
if (c == TEX_CACHE_MAX)
fatal("Texture cache full!\n");
c = voodoo->texture_last_removed;
if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR))
voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu];
else
voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu];
voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff;
lod_min = (params->tLOD[tmu] >> 2) & 15;
lod_max = (params->tLOD[tmu] >> 8) & 15;
// pclog(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu);
lod_min = MIN(lod_min, 8);
lod_max = MIN(lod_max, 8);
for (lod = lod_min; lod <= lod_max; lod++)
{
uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]];
uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask;
int x, y;
int shift = 8 - params->tex_lod[tmu][lod];
rgba_u *pal;
//pclog(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]);
switch (params->tformat[tmu])
{
case TEX_RGB332:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_Y4I2Q2:
pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0];
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_A8:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba(dat, dat, dat, dat);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_I8:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba(dat, dat, dat, 0xff);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_AI8:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f));
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_PAL8:
pal = voodoo->palette[tmu];
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_APAL8:
pal = voodoo->palette[tmu];
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask];
int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3);
int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2);
int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4);
int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6);
base[x] = makergba(r, g, b, a);
}
tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]);
base += (1 << shift);
}
break;
case TEX_ARGB8332:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_A8Y4I2Q2:
pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0];
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_R5G6B5:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_ARGB1555:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_ARGB4444:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_A8I8:
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
case TEX_APAL88:
pal = voodoo->palette[tmu];
for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++)
{
for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++)
{
uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask];
base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8);
}
tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1));
base += (1 << shift);
}
break;
default:
fatal("Unknown texture format %i\n", params->tformat[tmu]);
}
}
voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8;
if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88)
voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum;
else
voodoo->texture_cache[tmu][c].palette_checksum = 0;
if (lod_min == 0)
{
voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0];
voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0];
}
else
voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0;
if (lod_min <= 1 && lod_max >= 1)
{
voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1];
voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1];
}
else
voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0;
if (lod_min <= 2 && lod_max >= 2)
{
voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2];
voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2];
}
else
voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0;
if (lod_max >= 3)
{
voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3];
voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8];
}
else
voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0;
for (d = 0; d < 4; d++)
{
addr = voodoo->texture_cache[tmu][c].addr_start[d];
addr_end = voodoo->texture_cache[tmu][c].addr_end[d];
if (addr_end != 0)
{
for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT))
voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1;
}
}
params->tex_entry[tmu] = c;
voodoo->texture_cache[tmu][c].refcount++;
}
void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu)
{
int wait_for_idle = 0;
int c;
memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0]));
// pclog("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present));
for (c = 0; c < TEX_CACHE_MAX; c++)
{
if (voodoo->texture_cache[tmu][c].base != -1)
{
int d;
for (d = 0; d < 4; d++)
{
int addr_start = voodoo->texture_cache[tmu][c].addr_start[d];
int addr_end = voodoo->texture_cache[tmu][c].addr_end[d];
if (addr_end != 0)
{
int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff;
int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff;
if (addr_end_masked < addr_start_masked)
addr_end_masked = voodoo->texture_mask+1;
if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked)
{
// pclog(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base);
if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] ||
(voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1]))
wait_for_idle = 1;
voodoo->texture_cache[tmu][c].base = -1;
}
else
{
for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT))
voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1;
}
}
}
}
}
if (wait_for_idle)
voodoo_wait_for_render_thread_idle(voodoo);
}
void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p)
{
int lod, s, t;
voodoo_t *voodoo = (voodoo_t *)p;
int tmu;
if (addr & 0x400000)
return; /*TREX != 0*/
tmu = (addr & 0x200000) ? 1 : 0;
if (tmu && !voodoo->dual_tmus)
return;
if (voodoo->type < VOODOO_BANSHEE)
{
if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type >= VOODOO_BANSHEE)
{
lod = (addr >> 16) & 0xf;
t = (addr >> 8) & 0xff;
}
else
{
lod = (addr >> 17) & 0xf;
t = (addr >> 9) & 0xff;
}
if (voodoo->params.tformat[tmu] & 8)
s = (addr >> 1) & 0xfe;
else
{
if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type >= VOODOO_BANSHEE)
s = addr & 0xfc;
else
s = (addr >> 1) & 0xfc;
}
if (lod > LOD_MAX)
return;
// if (addr >= 0x200000)
// return;
if (voodoo->params.tformat[tmu] & 8)
addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2;
else
addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]);
}
else
addr = (addr & 0x1ffffc) + voodoo->params.tex_base[tmu][0];
if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT])
{
// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu);
}
if (voodoo->type == VOODOO_3 && voodoo->texture_present[tmu^1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT])
{
// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu^1);
}
*(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val;
}

19
pcem/vid_voodoo_texture.h Normal file
View File

@ -0,0 +1,19 @@
static const uint32_t texture_offset[LOD_MAX+3] =
{
0,
256*256,
256*256 + 128*128,
256*256 + 128*128 + 64*64,
256*256 + 128*128 + 64*64 + 32*32,
256*256 + 128*128 + 64*64 + 32*32 + 16*16,
256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8,
256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4,
256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2,
256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1,
256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1
};
void voodoo_recalc_tex(voodoo_t *voodoo, int tmu);
void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu);
void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p);
void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu);