IMG floppy image handler now fills the remaining bytes with 0xF6 if it has read less bytes than expected - fixes handling of truncated IMG's with a valid BPB; HDI files are now written with the correct header; FDC DUMP REGISTERS command is now implemented correctly, fixes FDC error on AMI 486 clone and AMI WinBIOS 486; Commented out the Acer 386SX and the Phoenix 386 clone; WinPCap code is now delayed loading (thanks to Rai-chan), the emulator should now be able to run without WinPCap installed if not using PCap; The IBM PS/2 Model 30 NVR file is now saved in the same directly as the other NVR files; Applied all the latest mainline PCem Voodoo commits.
7315 lines
298 KiB
C
7315 lines
298 KiB
C
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include "ibm.h"
|
|
#include "device.h"
|
|
#include "mem.h"
|
|
#include "pci.h"
|
|
#include "thread.h"
|
|
#include "timer.h"
|
|
#include "video.h"
|
|
#include "vid_svga.h"
|
|
#include "vid_voodoo.h"
|
|
#include "vid_voodoo_dither.h"
|
|
|
|
#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 = 1,
|
|
VOODOO_2 = 2
|
|
};
|
|
|
|
static 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
|
|
};
|
|
|
|
static int tris = 0;
|
|
|
|
static uint64_t status_time = 0;
|
|
static uint64_t voodoo_time = 0;
|
|
static int voodoo_render_time[2] = {0, 0};
|
|
static int voodoo_render_time_old[2] = {0, 0};
|
|
|
|
typedef union int_float
|
|
{
|
|
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)
|
|
#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)
|
|
};
|
|
|
|
#define PARAM_SIZE 1024
|
|
#define PARAM_MASK (PARAM_SIZE - 1)
|
|
#define PARAM_ENTRY_SIZE (1 << 31)
|
|
|
|
#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0])
|
|
#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1])
|
|
#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE)
|
|
#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE)
|
|
#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx)
|
|
#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx)
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t addr_type;
|
|
uint32_t val;
|
|
} fifo_entry_t;
|
|
|
|
static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000];
|
|
|
|
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];
|
|
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 sign;
|
|
|
|
uint32_t front_offset;
|
|
|
|
uint32_t swapbufferCMD;
|
|
|
|
uint32_t stipple;
|
|
} voodoo_params_t;
|
|
|
|
typedef struct texture_t
|
|
{
|
|
uint32_t base;
|
|
uint32_t tLOD;
|
|
volatile int refcount, refcount_r[2];
|
|
int is16;
|
|
uint32_t palette_checksum;
|
|
uint32_t addr_start, addr_end;
|
|
uint32_t *data;
|
|
} texture_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;
|
|
int line_time;
|
|
|
|
voodoo_params_t params;
|
|
|
|
uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4;
|
|
uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/
|
|
|
|
uint8_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;
|
|
int block_width;
|
|
|
|
uint8_t *fb_mem, *tex_mem[2];
|
|
uint16_t *tex_mem_w[2];
|
|
|
|
int rgb_sel;
|
|
|
|
uint32_t trexInit1[2];
|
|
|
|
int swap_count;
|
|
|
|
int disp_buffer, draw_buffer;
|
|
int timer_count;
|
|
|
|
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[2];
|
|
event_t *wake_fifo_thread;
|
|
event_t *wake_main_thread;
|
|
event_t *fifo_not_full_event;
|
|
event_t *render_not_full_event[2];
|
|
event_t *wake_render_thread[2];
|
|
|
|
int voodoo_busy;
|
|
int render_voodoo_busy[2];
|
|
|
|
int render_threads;
|
|
int odd_even_mask;
|
|
|
|
int pixel_count[2], texel_count[2], tri_count, frame_count;
|
|
int pixel_count_old[2], texel_count_old[2];
|
|
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;
|
|
int cmd_read, cmd_written;
|
|
|
|
voodoo_params_t params_buffer[PARAM_SIZE];
|
|
volatile int params_read_idx[2], params_write_idx;
|
|
|
|
uint32_t cmdfifo_base, cmdfifo_end;
|
|
int cmdfifo_rp;
|
|
volatile int cmdfifo_depth_rd, cmdfifo_depth_wr;
|
|
uint32_t cmdfifo_amin, cmdfifo_amax;
|
|
|
|
uint32_t sSetupMode;
|
|
struct
|
|
{
|
|
float sVx, sVy;
|
|
float sRed, sGreen, sBlue, sAlpha;
|
|
float sVz, sWb;
|
|
float sW0, sS0, sT0;
|
|
float sW1, sS1, sT1;
|
|
} verts[4];
|
|
int vertex_num;
|
|
int num_verticies;
|
|
|
|
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;
|
|
|
|
struct
|
|
{
|
|
int dst_x, dst_y;
|
|
int cur_x;
|
|
int size_x, size_y;
|
|
int x_dir, y_dir;
|
|
int dst_stride;
|
|
} blt;
|
|
|
|
rgb_t clutData[33];
|
|
int clutData_dirty;
|
|
rgb_t clutData256[256];
|
|
uint32_t video_16to32[0x10000];
|
|
|
|
uint8_t dirty_line[1024];
|
|
int dirty_line_low, dirty_line_high;
|
|
|
|
int fb_write_buffer, fb_draw_buffer;
|
|
int buffer_cutoff;
|
|
|
|
int read_time, write_time, burst_time;
|
|
|
|
int wake_timer;
|
|
|
|
uint8_t thefilter[256][256]; // pixel filter, feeding from one or two
|
|
uint8_t thefilterg[256][256]; // for green
|
|
uint8_t thefilterb[256][256]; // for blue
|
|
|
|
/* the voodoo adds purple lines for some reason */
|
|
uint16_t purpleline[256][3];
|
|
|
|
texture_t texture_cache[2][TEX_CACHE_MAX];
|
|
uint8_t texture_present[2][4096];
|
|
int texture_last_removed;
|
|
|
|
uint32_t palette_checksum[2];
|
|
int palette_dirty[2];
|
|
|
|
int use_recompiler;
|
|
void *codegen_data;
|
|
} voodoo_t;
|
|
|
|
static inline void wait_for_render_thread_idle(voodoo_t *voodoo);
|
|
|
|
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_fbiInit4 = 0x200,
|
|
|
|
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_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
|
|
{
|
|
FBIINIT3_REMAP = 1
|
|
};
|
|
|
|
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_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)
|
|
};
|
|
|
|
#define TEXTUREMODE_MASK 0x3ffff000
|
|
#define TEXTUREMODE_PASSTHROUGH 0
|
|
|
|
#define TEXTUREMODE_LOCAL_MASK 0x00643000
|
|
#define TEXTUREMODE_LOCAL 0x00241000
|
|
|
|
static void voodoo_threshold_check(voodoo_t *voodoo);
|
|
|
|
static 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 _y = (col >> 4), _i = (col >> 2) & 3, _q = col & 3;
|
|
int i_r, i_g, i_b;
|
|
int q_r, q_g, q_b;
|
|
int r, g, 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400)
|
|
static void voodoo_recalc(voodoo_t *voodoo)
|
|
{
|
|
uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096;
|
|
|
|
voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset;
|
|
voodoo->back_offset = voodoo->draw_buffer*buffer_offset;
|
|
|
|
voodoo->buffer_cutoff = TRIPLE_BUFFER ? (buffer_offset * 4) : (buffer_offset * 3);
|
|
if (TRIPLE_BUFFER)
|
|
voodoo->params.aux_offset = buffer_offset * 3;
|
|
else
|
|
voodoo->params.aux_offset = buffer_offset * 2;
|
|
|
|
switch (voodoo->lfbMode & LFB_WRITE_MASK)
|
|
{
|
|
case LFB_WRITE_FRONT:
|
|
voodoo->fb_write_offset = voodoo->params.front_offset;
|
|
voodoo->fb_write_buffer = voodoo->disp_buffer;
|
|
break;
|
|
case LFB_WRITE_BACK:
|
|
voodoo->fb_write_offset = voodoo->back_offset;
|
|
voodoo->fb_write_buffer = voodoo->draw_buffer;
|
|
break;
|
|
|
|
default:
|
|
/*BreakNeck sets invalid LFB write buffer select*/
|
|
voodoo->fb_write_offset = voodoo->params.front_offset;
|
|
break;
|
|
}
|
|
|
|
switch (voodoo->lfbMode & LFB_READ_MASK)
|
|
{
|
|
case LFB_READ_FRONT:
|
|
voodoo->fb_read_offset = voodoo->params.front_offset;
|
|
break;
|
|
case LFB_READ_BACK:
|
|
voodoo->fb_read_offset = voodoo->back_offset;
|
|
break;
|
|
case LFB_READ_AUX:
|
|
voodoo->fb_read_offset = voodoo->params.aux_offset;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_recalc : unknown lfb source\n");
|
|
}
|
|
|
|
switch (voodoo->params.fbzMode & FBZ_DRAW_MASK)
|
|
{
|
|
case FBZ_DRAW_FRONT:
|
|
voodoo->params.draw_offset = voodoo->params.front_offset;
|
|
voodoo->fb_draw_buffer = voodoo->disp_buffer;
|
|
break;
|
|
case FBZ_DRAW_BACK:
|
|
voodoo->params.draw_offset = voodoo->back_offset;
|
|
voodoo->fb_draw_buffer = voodoo->draw_buffer;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_recalc : unknown draw buffer\n");
|
|
}
|
|
|
|
voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2;
|
|
if (voodoo->fbiInit6 & (1 << 30))
|
|
voodoo->block_width += 1;
|
|
if (voodoo->fbiInit1 & (1 << 24))
|
|
voodoo->block_width += 32;
|
|
voodoo->row_width = voodoo->block_width * 32 * 2;
|
|
|
|
/* pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset);
|
|
pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode);*/
|
|
}
|
|
|
|
static 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;
|
|
int lod_min = (voodoo->params.tLOD[tmu] >> 2) & 15;
|
|
int lod_max = (voodoo->params.tLOD[tmu] >> 8) & 15;
|
|
uint32_t base = voodoo->params.texBaseAddr[tmu];
|
|
int tex_lod = 0;
|
|
|
|
if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER)
|
|
height >>= aspect;
|
|
else
|
|
{
|
|
width >>= aspect;
|
|
shift -= aspect;
|
|
}
|
|
|
|
if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD))
|
|
{
|
|
width >>= 1;
|
|
height >>= 1;
|
|
shift--;
|
|
tex_lod++;
|
|
}
|
|
|
|
for (lod = 0; lod <= LOD_MAX+1; lod++)
|
|
{
|
|
if (!width)
|
|
width = 1;
|
|
if (!height)
|
|
height = 1;
|
|
if (shift < 0)
|
|
shift = 0;
|
|
voodoo->params.tex_base[tmu][lod] = base;
|
|
voodoo->params.tex_w_mask[tmu][lod] = width - 1;
|
|
voodoo->params.tex_w_nmask[tmu][lod] = ~(width - 1);
|
|
voodoo->params.tex_h_mask[tmu][lod] = height - 1;
|
|
voodoo->params.tex_shift[tmu][lod] = shift;
|
|
voodoo->params.tex_lod[tmu][lod] = tex_lod;
|
|
|
|
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.tLOD[tmu] & LOD_ODD) || lod != 0)
|
|
{
|
|
if (voodoo->params.tformat[tmu] & 8)
|
|
base += width * height * 2;
|
|
else
|
|
base += width * height;
|
|
|
|
if (voodoo->params.tLOD[tmu] & LOD_SPLIT)
|
|
{
|
|
width >>= 2;
|
|
height >>= 2;
|
|
shift -= 2;
|
|
tex_lod += 2;
|
|
}
|
|
else
|
|
{
|
|
width >>= 1;
|
|
height >>= 1;
|
|
shift--;
|
|
tex_lod++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
voodoo->params.tex_width[tmu] = width;
|
|
}
|
|
|
|
#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24))
|
|
|
|
static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu)
|
|
{
|
|
int c;
|
|
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;
|
|
|
|
/*Try to find texture in cache*/
|
|
for (c = 0; c < TEX_CACHE_MAX; c++)
|
|
{
|
|
if (voodoo->texture_cache[tmu][c].base == params->texBaseAddr[tmu] &&
|
|
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)
|
|
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;
|
|
|
|
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\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max);
|
|
|
|
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_APAL88)
|
|
voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum;
|
|
else
|
|
voodoo->texture_cache[tmu][c].palette_checksum = 0;
|
|
|
|
addr = voodoo->params.tex_base[tmu][lod_min];
|
|
addr_end = voodoo->params.tex_base[tmu][lod_max+1];
|
|
voodoo->texture_cache[tmu][c].addr_start = addr;
|
|
voodoo->texture_cache[tmu][c].addr_end = addr_end;
|
|
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++;
|
|
}
|
|
|
|
static 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 lod_min = (voodoo->texture_cache[tmu][c].tLOD >> 2) & 15;
|
|
int lod_max = (voodoo->texture_cache[tmu][c].tLOD >> 8) & 15;
|
|
int addr_start = voodoo->texture_cache[tmu][c].addr_start;
|
|
int addr_end = voodoo->texture_cache[tmu][c].addr_end;
|
|
|
|
if (dirty_addr >= (addr_start & voodoo->texture_mask & ~0x3ff) && dirty_addr < (((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff))
|
|
{
|
|
// 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)
|
|
wait_for_render_thread_idle(voodoo);
|
|
}
|
|
|
|
typedef struct voodoo_state_t
|
|
{
|
|
int xstart, xend, xdir;
|
|
uint32_t base_r, base_g, base_b, base_a, base_z;
|
|
struct
|
|
{
|
|
int64_t base_s, base_t, base_w;
|
|
int lod;
|
|
} tmu[2];
|
|
int64_t base_w;
|
|
int lod;
|
|
int lod_min[2], lod_max[2];
|
|
int dx1, dx2;
|
|
int y, yend, ydir;
|
|
int32_t dxAB, dxAC, dxBC;
|
|
int tex_b[2], tex_g[2], tex_r[2], tex_a[2];
|
|
int tex_s, tex_t;
|
|
int clamp_s[2], clamp_t[2];
|
|
|
|
int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy;
|
|
|
|
uint32_t *tex[2][LOD_MAX+1];
|
|
int tformat;
|
|
|
|
int *tex_w_mask[2];
|
|
int *tex_h_mask[2];
|
|
int *tex_shift[2];
|
|
int *tex_lod[2];
|
|
|
|
uint16_t *fb_mem, *aux_mem;
|
|
|
|
int32_t ib, ig, ir, ia;
|
|
int32_t z;
|
|
|
|
int32_t new_depth;
|
|
|
|
int64_t tmu0_s, tmu0_t;
|
|
int64_t tmu0_w;
|
|
int64_t tmu1_s, tmu1_t;
|
|
int64_t tmu1_w;
|
|
int64_t w;
|
|
|
|
int pixel_count, texel_count;
|
|
int x, x2;
|
|
|
|
uint32_t w_depth;
|
|
|
|
float log_temp;
|
|
uint32_t ebp_store;
|
|
uint32_t texBaseAddr;
|
|
|
|
int lod_frac[2];
|
|
} voodoo_state_t;
|
|
|
|
static int voodoo_output = 0;
|
|
|
|
static uint8_t logtable[256] =
|
|
{
|
|
0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15,
|
|
0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a,
|
|
0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e,
|
|
0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51,
|
|
0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63,
|
|
0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,
|
|
0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85,
|
|
0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
|
|
0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3,
|
|
0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2,
|
|
0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0,
|
|
0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd,
|
|
0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda,
|
|
0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7,
|
|
0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3,
|
|
0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff
|
|
};
|
|
|
|
static inline int fastlog(uint64_t val)
|
|
{
|
|
uint64_t oldval = val;
|
|
int exp = 63;
|
|
int frac;
|
|
|
|
if (!val || val & (1ULL << 63))
|
|
return 0x80000000;
|
|
|
|
if (!(val & 0xffffffff00000000))
|
|
{
|
|
exp -= 32;
|
|
val <<= 32;
|
|
}
|
|
if (!(val & 0xffff000000000000))
|
|
{
|
|
exp -= 16;
|
|
val <<= 16;
|
|
}
|
|
if (!(val & 0xff00000000000000))
|
|
{
|
|
exp -= 8;
|
|
val <<= 8;
|
|
}
|
|
if (!(val & 0xf000000000000000))
|
|
{
|
|
exp -= 4;
|
|
val <<= 4;
|
|
}
|
|
if (!(val & 0xc000000000000000))
|
|
{
|
|
exp -= 2;
|
|
val <<= 2;
|
|
}
|
|
if (!(val & 0x8000000000000000))
|
|
{
|
|
exp -= 1;
|
|
val <<= 1;
|
|
}
|
|
|
|
if (exp >= 8)
|
|
frac = (oldval >> (exp - 8)) & 0xff;
|
|
else
|
|
frac = (oldval << (8 - exp)) & 0xff;
|
|
|
|
return (exp << 8) | logtable[frac];
|
|
}
|
|
|
|
static inline int fls(uint16_t val)
|
|
{
|
|
int num = 0;
|
|
|
|
//pclog("fls(%04x) = ", val);
|
|
if (!(val & 0xff00))
|
|
{
|
|
num += 8;
|
|
val <<= 8;
|
|
}
|
|
if (!(val & 0xf000))
|
|
{
|
|
num += 4;
|
|
val <<= 4;
|
|
}
|
|
if (!(val & 0xc000))
|
|
{
|
|
num += 2;
|
|
val <<= 2;
|
|
}
|
|
if (!(val & 0x8000))
|
|
{
|
|
num += 1;
|
|
val <<= 1;
|
|
}
|
|
//pclog("%i %04x\n", num, val);
|
|
return num;
|
|
}
|
|
|
|
typedef struct voodoo_texture_state_t
|
|
{
|
|
int s, t;
|
|
int w_mask, h_mask;
|
|
int tex_shift;
|
|
} voodoo_texture_state_t;
|
|
|
|
static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int tmu)
|
|
{
|
|
uint32_t dat;
|
|
|
|
if (texture_state->s & ~texture_state->w_mask)
|
|
{
|
|
if (state->clamp_s[tmu])
|
|
{
|
|
if (texture_state->s < 0)
|
|
texture_state->s = 0;
|
|
if (texture_state->s > texture_state->w_mask)
|
|
texture_state->s = texture_state->w_mask;
|
|
}
|
|
else
|
|
texture_state->s &= texture_state->w_mask;
|
|
}
|
|
if (texture_state->t & ~texture_state->h_mask)
|
|
{
|
|
if (state->clamp_t[tmu])
|
|
{
|
|
if (texture_state->t < 0)
|
|
texture_state->t = 0;
|
|
if (texture_state->t > texture_state->h_mask)
|
|
texture_state->t = texture_state->h_mask;
|
|
}
|
|
else
|
|
texture_state->t &= texture_state->h_mask;
|
|
}
|
|
|
|
dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)];
|
|
|
|
state->tex_b[tmu] = dat & 0xff;
|
|
state->tex_g[tmu] = (dat >> 8) & 0xff;
|
|
state->tex_r[tmu] = (dat >> 16) & 0xff;
|
|
state->tex_a[tmu] = (dat >> 24) & 0xff;
|
|
}
|
|
|
|
#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4))
|
|
#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4))
|
|
|
|
static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d, int tmu, int x)
|
|
{
|
|
rgba_u dat[4];
|
|
|
|
if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask))
|
|
{
|
|
int c;
|
|
for (c = 0; c < 4; c++)
|
|
{
|
|
int _s = s + (c & 1);
|
|
int _t = t + ((c & 2) >> 1);
|
|
|
|
if (_s & ~texture_state->w_mask)
|
|
{
|
|
if (state->clamp_s[tmu])
|
|
{
|
|
if (_s < 0)
|
|
_s = 0;
|
|
if (_s > texture_state->w_mask)
|
|
_s = texture_state->w_mask;
|
|
}
|
|
else
|
|
_s &= texture_state->w_mask;
|
|
}
|
|
if (_t & ~texture_state->h_mask)
|
|
{
|
|
if (state->clamp_t[tmu])
|
|
{
|
|
if (_t < 0)
|
|
_t = 0;
|
|
if (_t > texture_state->h_mask)
|
|
_t = texture_state->h_mask;
|
|
}
|
|
else
|
|
_t &= texture_state->h_mask;
|
|
}
|
|
dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)];
|
|
dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)];
|
|
dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)];
|
|
dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)];
|
|
}
|
|
|
|
state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8;
|
|
state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8;
|
|
state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8;
|
|
state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8;
|
|
}
|
|
|
|
static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x)
|
|
{
|
|
rgba_u tex_samples[4];
|
|
voodoo_texture_state_t texture_state;
|
|
int d[4];
|
|
int s, t;
|
|
int tex_lod = state->tex_lod[tmu][state->lod];
|
|
|
|
texture_state.w_mask = state->tex_w_mask[tmu][state->lod];
|
|
texture_state.h_mask = state->tex_h_mask[tmu][state->lod];
|
|
texture_state.tex_shift = 8 - tex_lod;
|
|
|
|
if (params->tLOD[tmu] & LOD_TMIRROR_S)
|
|
{
|
|
if (state->tex_s & 0x1000)
|
|
state->tex_s = ~state->tex_s;
|
|
}
|
|
if (params->tLOD[tmu] & LOD_TMIRROR_T)
|
|
{
|
|
if (state->tex_t & 0x1000)
|
|
state->tex_t = ~state->tex_t;
|
|
}
|
|
|
|
if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6)
|
|
{
|
|
int _ds, dt;
|
|
|
|
state->tex_s -= 1 << (3+tex_lod);
|
|
state->tex_t -= 1 << (3+tex_lod);
|
|
|
|
s = state->tex_s >> tex_lod;
|
|
t = state->tex_t >> tex_lod;
|
|
|
|
_ds = s & 0xf;
|
|
dt = t & 0xf;
|
|
|
|
s >>= 4;
|
|
t >>= 4;
|
|
//if (x == 80)
|
|
//if (voodoo_output)
|
|
// pclog("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt);
|
|
d[0] = (16 - _ds) * (16 - dt);
|
|
d[1] = _ds * (16 - dt);
|
|
d[2] = (16 - _ds) * dt;
|
|
d[3] = _ds * dt;
|
|
|
|
// texture_state.s = s;
|
|
// texture_state.t = t;
|
|
tex_read_4(state, &texture_state, s, t, d, tmu, x);
|
|
|
|
|
|
/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8;
|
|
state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8;
|
|
state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8;
|
|
state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/
|
|
/* state->tex_r = tex_samples[0].r;
|
|
state->tex_g = tex_samples[0].g;
|
|
state->tex_b = tex_samples[0].b;
|
|
state->tex_a = tex_samples[0].a;*/
|
|
}
|
|
else
|
|
{
|
|
// rgba_t tex_samples;
|
|
// voodoo_texture_state_t texture_state;
|
|
// int s = state->tex_s >> (18+state->lod);
|
|
// int t = state->tex_t >> (18+state->lod);
|
|
// int s, t;
|
|
|
|
// state->tex_s -= 1 << (17+state->lod);
|
|
// state->tex_t -= 1 << (17+state->lod);
|
|
|
|
s = state->tex_s >> (4+tex_lod);
|
|
t = state->tex_t >> (4+tex_lod);
|
|
|
|
texture_state.s = s;
|
|
texture_state.t = t;
|
|
tex_read(state, &texture_state, tmu);
|
|
|
|
/* state->tex_r = tex_samples[0].rgba.r;
|
|
state->tex_g = tex_samples[0].rgba.g;
|
|
state->tex_b = tex_samples[0].rgba.b;
|
|
state->tex_a = tex_samples[0].rgba.a;*/
|
|
}
|
|
}
|
|
|
|
static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x)
|
|
{
|
|
if (params->textureMode[tmu] & 1)
|
|
{
|
|
int64_t _w = 0;
|
|
|
|
if (tmu)
|
|
{
|
|
if (state->tmu1_w)
|
|
_w = (int64_t)((1ULL << 48) / state->tmu1_w);
|
|
state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30);
|
|
state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30);
|
|
}
|
|
else
|
|
{
|
|
if (state->tmu0_w)
|
|
_w = (int64_t)((1ULL << 48) / state->tmu0_w);
|
|
state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30);
|
|
state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30);
|
|
}
|
|
|
|
state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8));
|
|
}
|
|
else
|
|
{
|
|
if (tmu)
|
|
{
|
|
state->tex_s = (int32_t)(state->tmu1_s >> (14+14));
|
|
state->tex_t = (int32_t)(state->tmu1_t >> (14+14));
|
|
}
|
|
else
|
|
{
|
|
state->tex_s = (int32_t)(state->tmu0_s >> (14+14));
|
|
state->tex_t = (int32_t)(state->tmu0_t >> (14+14));
|
|
}
|
|
state->lod = state->tmu[tmu].lod;
|
|
}
|
|
|
|
if (state->lod < state->lod_min[tmu])
|
|
state->lod = state->lod_min[tmu];
|
|
else if (state->lod > state->lod_max[tmu])
|
|
state->lod = state->lod_max[tmu];
|
|
state->lod_frac[tmu] = state->lod & 0xff;
|
|
state->lod >>= 8;
|
|
|
|
voodoo_get_texture(voodoo, params, state, tmu, x);
|
|
}
|
|
|
|
#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; \
|
|
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, newdest_g, newdest_b; \
|
|
\
|
|
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)
|
|
|
|
|
|
#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)
|
|
|
|
/*Perform texture fetch and blending for both TMUs*/
|
|
static inline voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x)
|
|
{
|
|
int r,g,b,a;
|
|
int c_reverse, a_reverse;
|
|
int c_reverse1, a_reverse1;
|
|
int factor_r, factor_g, factor_b, factor_a;
|
|
|
|
voodoo_tmu_fetch(voodoo, params, state, 1, x);
|
|
|
|
if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1))
|
|
{
|
|
c_reverse = tc_reverse_blend;
|
|
a_reverse = tca_reverse_blend;
|
|
}
|
|
else
|
|
{
|
|
c_reverse = !tc_reverse_blend;
|
|
a_reverse = !tca_reverse_blend;
|
|
}
|
|
c_reverse1 = c_reverse;
|
|
a_reverse1 = a_reverse;
|
|
if (tc_sub_clocal_1)
|
|
{
|
|
switch (tc_mselect_1)
|
|
{
|
|
case TC_MSELECT_ZERO:
|
|
factor_r = factor_g = factor_b = 0;
|
|
break;
|
|
case TC_MSELECT_CLOCAL:
|
|
factor_r = state->tex_r[1];
|
|
factor_g = state->tex_g[1];
|
|
factor_b = state->tex_b[1];
|
|
break;
|
|
case TC_MSELECT_AOTHER:
|
|
factor_r = factor_g = factor_b = 0;
|
|
break;
|
|
case TC_MSELECT_ALOCAL:
|
|
factor_r = factor_g = factor_b = state->tex_a[1];
|
|
break;
|
|
case TC_MSELECT_DETAIL:
|
|
factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1];
|
|
if (factor_r > params->detail_max[1])
|
|
factor_r = params->detail_max[1];
|
|
factor_g = factor_b = factor_r;
|
|
break;
|
|
case TC_MSELECT_LOD_FRAC:
|
|
factor_r = factor_g = factor_b = state->lod_frac[1];
|
|
break;
|
|
}
|
|
if (!c_reverse)
|
|
{
|
|
r = (-state->tex_r[1] * (factor_r + 1)) >> 8;
|
|
g = (-state->tex_g[1] * (factor_g + 1)) >> 8;
|
|
b = (-state->tex_b[1] * (factor_b + 1)) >> 8;
|
|
}
|
|
else
|
|
{
|
|
r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8;
|
|
g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8;
|
|
b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8;
|
|
}
|
|
if (tc_add_clocal_1)
|
|
{
|
|
r += state->tex_r[1];
|
|
g += state->tex_g[1];
|
|
b += state->tex_b[1];
|
|
}
|
|
else if (tc_add_alocal_1)
|
|
{
|
|
r += state->tex_a[1];
|
|
g += state->tex_a[1];
|
|
b += state->tex_a[1];
|
|
}
|
|
state->tex_r[1] = CLAMP(r);
|
|
state->tex_g[1] = CLAMP(g);
|
|
state->tex_b[1] = CLAMP(b);
|
|
}
|
|
if (tca_sub_clocal_1)
|
|
{
|
|
switch (tca_mselect_1)
|
|
{
|
|
case TCA_MSELECT_ZERO:
|
|
factor_a = 0;
|
|
break;
|
|
case TCA_MSELECT_CLOCAL:
|
|
factor_a = state->tex_a[1];
|
|
break;
|
|
case TCA_MSELECT_AOTHER:
|
|
factor_a = 0;
|
|
break;
|
|
case TCA_MSELECT_ALOCAL:
|
|
factor_a = state->tex_a[1];
|
|
break;
|
|
case TCA_MSELECT_DETAIL:
|
|
factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1];
|
|
if (factor_a > params->detail_max[1])
|
|
factor_a = params->detail_max[1];
|
|
break;
|
|
case TCA_MSELECT_LOD_FRAC:
|
|
factor_a = state->lod_frac[1];
|
|
break;
|
|
}
|
|
if (!a_reverse)
|
|
a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8;
|
|
else
|
|
a = (-state->tex_a[1] * (factor_a + 1)) >> 8;
|
|
if (tca_add_clocal_1 || tca_add_alocal_1)
|
|
a += state->tex_a[1];
|
|
state->tex_a[1] = CLAMP(a);
|
|
}
|
|
|
|
|
|
voodoo_tmu_fetch(voodoo, params, state, 0, x);
|
|
|
|
if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1))
|
|
{
|
|
c_reverse = tc_reverse_blend;
|
|
a_reverse = tca_reverse_blend;
|
|
}
|
|
else
|
|
{
|
|
c_reverse = !tc_reverse_blend;
|
|
a_reverse = !tca_reverse_blend;
|
|
}
|
|
|
|
if (!tc_zero_other)
|
|
{
|
|
r = state->tex_r[1];
|
|
g = state->tex_g[1];
|
|
b = state->tex_b[1];
|
|
}
|
|
else
|
|
r = g = b = 0;
|
|
if (tc_sub_clocal)
|
|
{
|
|
r -= state->tex_r[0];
|
|
g -= state->tex_g[0];
|
|
b -= state->tex_b[0];
|
|
}
|
|
switch (tc_mselect)
|
|
{
|
|
case TC_MSELECT_ZERO:
|
|
factor_r = factor_g = factor_b = 0;
|
|
break;
|
|
case TC_MSELECT_CLOCAL:
|
|
factor_r = state->tex_r[0];
|
|
factor_g = state->tex_g[0];
|
|
factor_b = state->tex_b[0];
|
|
break;
|
|
case TC_MSELECT_AOTHER:
|
|
factor_r = factor_g = factor_b = state->tex_a[1];
|
|
break;
|
|
case TC_MSELECT_ALOCAL:
|
|
factor_r = factor_g = factor_b = state->tex_a[0];
|
|
break;
|
|
case TC_MSELECT_DETAIL:
|
|
factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0];
|
|
if (factor_r > params->detail_max[0])
|
|
factor_r = params->detail_max[0];
|
|
factor_g = factor_b = factor_r;
|
|
break;
|
|
case TC_MSELECT_LOD_FRAC:
|
|
factor_r = factor_g = factor_b = state->lod_frac[0];
|
|
break;
|
|
}
|
|
if (!c_reverse)
|
|
{
|
|
r = (r * (factor_r + 1)) >> 8;
|
|
g = (g * (factor_g + 1)) >> 8;
|
|
b = (b * (factor_b + 1)) >> 8;
|
|
}
|
|
else
|
|
{
|
|
r = (r * ((factor_r^0xff) + 1)) >> 8;
|
|
g = (g * ((factor_g^0xff) + 1)) >> 8;
|
|
b = (b * ((factor_b^0xff) + 1)) >> 8;
|
|
}
|
|
if (tc_add_clocal)
|
|
{
|
|
r += state->tex_r[0];
|
|
g += state->tex_g[0];
|
|
b += state->tex_b[0];
|
|
}
|
|
else if (tc_add_alocal)
|
|
{
|
|
r += state->tex_a[0];
|
|
g += state->tex_a[0];
|
|
b += state->tex_a[0];
|
|
}
|
|
|
|
if (!tca_zero_other)
|
|
a = state->tex_a[1];
|
|
else
|
|
a = 0;
|
|
if (tca_sub_clocal)
|
|
a -= state->tex_a[0];
|
|
switch (tca_mselect)
|
|
{
|
|
case TCA_MSELECT_ZERO:
|
|
factor_a = 0;
|
|
break;
|
|
case TCA_MSELECT_CLOCAL:
|
|
factor_a = state->tex_a[0];
|
|
break;
|
|
case TCA_MSELECT_AOTHER:
|
|
factor_a = state->tex_a[1];
|
|
break;
|
|
case TCA_MSELECT_ALOCAL:
|
|
factor_a = state->tex_a[0];
|
|
break;
|
|
case TCA_MSELECT_DETAIL:
|
|
factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0];
|
|
if (factor_a > params->detail_max[0])
|
|
factor_a = params->detail_max[0];
|
|
break;
|
|
case TCA_MSELECT_LOD_FRAC:
|
|
factor_a = state->lod_frac[0];
|
|
break;
|
|
}
|
|
if (a_reverse)
|
|
a = (a * ((factor_a ^ 0xff) + 1)) >> 8;
|
|
else
|
|
a = (a * (factor_a + 1)) >> 8;
|
|
if (tca_add_clocal || tca_add_alocal)
|
|
a += state->tex_a[0];
|
|
|
|
|
|
state->tex_r[0] = CLAMP(r);
|
|
state->tex_g[0] = CLAMP(g);
|
|
state->tex_b[0] = CLAMP(b);
|
|
state->tex_a[0] = CLAMP(a);
|
|
|
|
if (tc_invert_output)
|
|
{
|
|
state->tex_r[0] ^= 0xff;
|
|
state->tex_g[0] ^= 0xff;
|
|
state->tex_b[0] ^= 0xff;
|
|
}
|
|
if (tca_invert_output)
|
|
state->tex_a[0] ^= 0xff;
|
|
}
|
|
|
|
#if (defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32) && !(defined __amd64__)
|
|
#include "vid_voodoo_codegen_x86.h"
|
|
#elif (defined __amd64__)
|
|
#include "vid_voodoo_codegen_x86-64.h"
|
|
#else
|
|
#define NO_CODEGEN
|
|
static int voodoo_recomp = 0;
|
|
#endif
|
|
|
|
static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even)
|
|
{
|
|
/* int rgb_sel = params->fbzColorPath & 3;
|
|
int a_sel = (params->fbzColorPath >> 2) & 3;
|
|
int cc_localselect = params->fbzColorPath & (1 << 4);
|
|
int cca_localselect = (params->fbzColorPath >> 5) & 3;
|
|
int cc_localselect_override = params->fbzColorPath & (1 << 7);
|
|
int cc_zero_other = params->fbzColorPath & (1 << 8);
|
|
int cc_sub_clocal = params->fbzColorPath & (1 << 9);
|
|
int cc_mselect = (params->fbzColorPath >> 10) & 7;
|
|
int cc_reverse_blend = params->fbzColorPath & (1 << 13);
|
|
int cc_add = (params->fbzColorPath >> 14) & 3;
|
|
int cc_add_alocal = params->fbzColorPath & (1 << 15);
|
|
int cc_invert_output = params->fbzColorPath & (1 << 16);
|
|
int cca_zero_other = params->fbzColorPath & (1 << 17);
|
|
int cca_sub_clocal = params->fbzColorPath & (1 << 18);
|
|
int cca_mselect = (params->fbzColorPath >> 19) & 7;
|
|
int cca_reverse_blend = params->fbzColorPath & (1 << 22);
|
|
int cca_add = (params->fbzColorPath >> 23) & 3;
|
|
int cca_invert_output = params->fbzColorPath & (1 << 25);
|
|
int src_afunc = (params->alphaMode >> 8) & 0xf;
|
|
int dest_afunc = (params->alphaMode >> 12) & 0xf;
|
|
int alpha_func = (params->alphaMode >> 1) & 7;
|
|
int a_ref = params->alphaMode >> 24;
|
|
int depth_op = (params->fbzMode >> 5) & 7;
|
|
int dither = params->fbzMode & FBZ_DITHER;*/
|
|
int texels;
|
|
int c;
|
|
uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y);
|
|
|
|
if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH ||
|
|
(params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL)
|
|
texels = 1;
|
|
else
|
|
texels = 2;
|
|
|
|
state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS;
|
|
state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT;
|
|
state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS;
|
|
state->clamp_t[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPT;
|
|
// int last_x;
|
|
// pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir);
|
|
|
|
for (c = 0; c <= LOD_MAX; c++)
|
|
{
|
|
state->tex[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]];
|
|
state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]];
|
|
}
|
|
|
|
state->tformat = params->tformat[0];
|
|
|
|
state->tex_w_mask[0] = params->tex_w_mask[0];
|
|
state->tex_h_mask[0] = params->tex_h_mask[0];
|
|
state->tex_shift[0] = params->tex_shift[0];
|
|
state->tex_lod[0] = params->tex_lod[0];
|
|
state->tex_w_mask[1] = params->tex_w_mask[1];
|
|
state->tex_h_mask[1] = params->tex_h_mask[1];
|
|
state->tex_shift[1] = params->tex_shift[1];
|
|
state->tex_lod[1] = params->tex_lod[1];
|
|
|
|
if ((params->fbzMode & 1) && (ystart < params->clipLowY))
|
|
{
|
|
int dy = params->clipLowY - ystart;
|
|
|
|
state->base_r += params->dRdY*dy;
|
|
state->base_g += params->dGdY*dy;
|
|
state->base_b += params->dBdY*dy;
|
|
state->base_a += params->dAdY*dy;
|
|
state->base_z += params->dZdY*dy;
|
|
state->tmu[0].base_s += params->tmu[0].dSdY*dy;
|
|
state->tmu[0].base_t += params->tmu[0].dTdY*dy;
|
|
state->tmu[0].base_w += params->tmu[0].dWdY*dy;
|
|
state->tmu[1].base_s += params->tmu[1].dSdY*dy;
|
|
state->tmu[1].base_t += params->tmu[1].dTdY*dy;
|
|
state->tmu[1].base_w += params->tmu[1].dWdY*dy;
|
|
state->base_w += params->dWdY*dy;
|
|
state->xstart += state->dx1*dy;
|
|
state->xend += state->dx2*dy;
|
|
|
|
ystart = params->clipLowY;
|
|
}
|
|
|
|
if ((params->fbzMode & 1) && (yend > params->clipHighY))
|
|
yend = params->clipHighY;
|
|
|
|
state->y = ystart;
|
|
// yend--;
|
|
|
|
#ifndef NO_CODEGEN
|
|
if (voodoo->use_recompiler)
|
|
voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even);
|
|
#endif
|
|
|
|
if (voodoo_output)
|
|
pclog("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC);
|
|
// pclog("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17));
|
|
for (; state->y < yend; state->y++)
|
|
{
|
|
int x, x2;
|
|
int real_y = (state->y << 4) + 8;
|
|
int start_x, start_x2;
|
|
int dx;
|
|
uint16_t *fb_mem, *aux_mem;
|
|
|
|
state->ir = state->base_r;
|
|
state->ig = state->base_g;
|
|
state->ib = state->base_b;
|
|
state->ia = state->base_a;
|
|
state->z = state->base_z;
|
|
state->tmu0_s = state->tmu[0].base_s;
|
|
state->tmu0_t = state->tmu[0].base_t;
|
|
state->tmu0_w = state->tmu[0].base_w;
|
|
state->tmu1_s = state->tmu[1].base_s;
|
|
state->tmu1_t = state->tmu[1].base_t;
|
|
state->tmu1_w = state->tmu[1].base_w;
|
|
state->w = state->base_w;
|
|
|
|
x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4);
|
|
|
|
if (real_y < state->vertexBy)
|
|
x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4);
|
|
else
|
|
x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4);
|
|
|
|
if (params->fbzMode & (1 << 17))
|
|
real_y = (voodoo->v_disp-1) - (real_y >> 4);
|
|
else
|
|
real_y >>= 4;
|
|
|
|
if ((real_y & voodoo->odd_even_mask) != odd_even)
|
|
goto next_line;
|
|
|
|
start_x = x;
|
|
|
|
if (state->xdir > 0)
|
|
x2 -= (1 << 16);
|
|
else
|
|
x -= (1 << 16);
|
|
dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16);
|
|
start_x2 = x + 0x7000;
|
|
x = (x + 0x7000) >> 16;
|
|
x2 = (x2 + 0x7000) >> 16;
|
|
|
|
if (voodoo_output)
|
|
pclog("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t);
|
|
|
|
state->ir += (params->dRdX * dx);
|
|
state->ig += (params->dGdX * dx);
|
|
state->ib += (params->dBdX * dx);
|
|
state->ia += (params->dAdX * dx);
|
|
state->z += (params->dZdX * dx);
|
|
state->tmu0_s += (params->tmu[0].dSdX * dx);
|
|
state->tmu0_t += (params->tmu[0].dTdX * dx);
|
|
state->tmu0_w += (params->tmu[0].dWdX * dx);
|
|
state->tmu1_s += (params->tmu[1].dSdX * dx);
|
|
state->tmu1_t += (params->tmu[1].dTdX * dx);
|
|
state->tmu1_w += (params->tmu[1].dWdX * dx);
|
|
state->w += (params->dWdX * dx);
|
|
|
|
if (voodoo_output)
|
|
pclog("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << 17+state->lod)) >> (18+state->lod));
|
|
|
|
if (params->fbzMode & 1)
|
|
{
|
|
if (state->xdir > 0)
|
|
{
|
|
if (x < params->clipLeft)
|
|
{
|
|
int dx = params->clipLeft - x;
|
|
|
|
state->ir += params->dRdX*dx;
|
|
state->ig += params->dGdX*dx;
|
|
state->ib += params->dBdX*dx;
|
|
state->ia += params->dAdX*dx;
|
|
state->z += params->dZdX*dx;
|
|
state->tmu0_s += params->tmu[0].dSdX*dx;
|
|
state->tmu0_t += params->tmu[0].dTdX*dx;
|
|
state->tmu0_w += params->tmu[0].dWdX*dx;
|
|
state->tmu1_s += params->tmu[1].dSdX*dx;
|
|
state->tmu1_t += params->tmu[1].dTdX*dx;
|
|
state->tmu1_w += params->tmu[1].dWdX*dx;
|
|
state->w += params->dWdX*dx;
|
|
|
|
x = params->clipLeft;
|
|
}
|
|
if (x2 > params->clipRight)
|
|
x2 = params->clipRight;
|
|
}
|
|
else
|
|
{
|
|
if (x > params->clipRight)
|
|
{
|
|
int dx = params->clipRight - x;
|
|
|
|
state->ir += params->dRdX*dx;
|
|
state->ig += params->dGdX*dx;
|
|
state->ib += params->dBdX*dx;
|
|
state->ia += params->dAdX*dx;
|
|
state->z += params->dZdX*dx;
|
|
state->tmu0_s += params->tmu[0].dSdX*dx;
|
|
state->tmu0_t += params->tmu[0].dTdX*dx;
|
|
state->tmu0_w += params->tmu[0].dWdX*dx;
|
|
state->tmu1_s += params->tmu[1].dSdX*dx;
|
|
state->tmu1_t += params->tmu[1].dTdX*dx;
|
|
state->tmu1_w += params->tmu[1].dWdX*dx;
|
|
state->w += params->dWdX*dx;
|
|
|
|
x = params->clipRight;
|
|
}
|
|
if (x2 < params->clipLeft)
|
|
x2 = params->clipLeft;
|
|
}
|
|
}
|
|
|
|
if (x2 < x && state->xdir > 0)
|
|
goto next_line;
|
|
if (x2 > x && state->xdir < 0)
|
|
goto next_line;
|
|
|
|
state->fb_mem = fb_mem = &voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)];
|
|
state->aux_mem = aux_mem = &voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask];
|
|
|
|
if (voodoo_output)
|
|
pclog("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2);
|
|
|
|
state->pixel_count = 0;
|
|
state->texel_count = 0;
|
|
state->x = x;
|
|
state->x2 = x2;
|
|
|
|
#ifndef NO_CODEGEN
|
|
if (voodoo->use_recompiler)
|
|
{
|
|
voodoo_draw(state, params, x, real_y);
|
|
}
|
|
else
|
|
#endif
|
|
do
|
|
{
|
|
start_x = x;
|
|
state->x = x;
|
|
voodoo->pixel_count[odd_even]++;
|
|
voodoo->texel_count[odd_even] += texels;
|
|
voodoo->fbiPixelsIn++;
|
|
|
|
if (voodoo_output)
|
|
pclog(" X=%03i T=%08x\n", x, state->tmu0_t);
|
|
// if (voodoo->fbzMode & FBZ_RGB_WMASK)
|
|
{
|
|
int update = 1;
|
|
uint8_t cother_r, cother_g, cother_b, aother;
|
|
uint8_t clocal_r, clocal_g, clocal_b, alocal;
|
|
int src_r, src_g, src_b, src_a;
|
|
int msel_r, msel_g, msel_b, msel_a;
|
|
uint8_t dest_r, dest_g, dest_b, dest_a;
|
|
uint16_t dat;
|
|
uint16_t aux_dat;
|
|
int sel;
|
|
int32_t new_depth, w_depth;
|
|
|
|
if (state->w & 0xffff00000000)
|
|
w_depth = 0;
|
|
else if (!(state->w & 0xffff0000))
|
|
w_depth = 0xf001;
|
|
else
|
|
{
|
|
int exp = fls((uint16_t)((uint32_t)state->w >> 16));
|
|
int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff;
|
|
w_depth = (exp << 12) + mant + 1;
|
|
if (w_depth > 0xffff)
|
|
w_depth = 0xffff;
|
|
}
|
|
|
|
// w_depth = CLAMP16(w_depth);
|
|
|
|
if (params->fbzMode & FBZ_W_BUFFER)
|
|
new_depth = w_depth;
|
|
else
|
|
new_depth = CLAMP16(state->z >> 12);
|
|
|
|
if (params->fbzMode & FBZ_DEPTH_BIAS)
|
|
new_depth = CLAMP16(new_depth + (int16_t)params->zaColor);
|
|
|
|
if (params->fbzMode & FBZ_DEPTH_ENABLE)
|
|
{
|
|
uint16_t old_depth = aux_mem[x];
|
|
|
|
DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth);
|
|
}
|
|
|
|
dat = fb_mem[x];
|
|
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;
|
|
|
|
if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED)
|
|
{
|
|
if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus)
|
|
{
|
|
/*TMU0 only sampling local colour or only one TMU, only sample TMU0*/
|
|
voodoo_tmu_fetch(voodoo, params, state, 0, x);
|
|
}
|
|
else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH)
|
|
{
|
|
/*TMU0 in pass-through mode, only sample TMU1*/
|
|
voodoo_tmu_fetch(voodoo, params, state, 1, x);
|
|
|
|
state->tex_r[0] = state->tex_r[1];
|
|
state->tex_g[0] = state->tex_g[1];
|
|
state->tex_b[0] = state->tex_b[1];
|
|
state->tex_a[0] = state->tex_a[1];
|
|
}
|
|
else
|
|
{
|
|
voodoo_tmu_fetch_and_blend(voodoo, params, state, x);
|
|
}
|
|
|
|
if ((params->fbzMode & FBZ_CHROMAKEY) &&
|
|
state->tex_r[0] == params->chromaKey_r &&
|
|
state->tex_g[0] == params->chromaKey_g &&
|
|
state->tex_b[0] == params->chromaKey_b)
|
|
{
|
|
voodoo->fbiChromaFail++;
|
|
goto skip_pixel;
|
|
}
|
|
}
|
|
|
|
if (voodoo->trexInit1[0] & (1 << 18))
|
|
{
|
|
state->tex_r[0] = state->tex_g[0] = 0;
|
|
|
|
if (voodoo->dual_tmus)
|
|
state->tex_b[0] = 1 | (3 << 6);
|
|
else
|
|
state->tex_b[0] = 1;
|
|
}
|
|
|
|
if (cc_localselect_override)
|
|
sel = (state->tex_a[0] & 0x80) ? 1 : 0;
|
|
else
|
|
sel = cc_localselect;
|
|
|
|
if (sel)
|
|
{
|
|
clocal_r = (params->color0 >> 16) & 0xff;
|
|
clocal_g = (params->color0 >> 8) & 0xff;
|
|
clocal_b = params->color0 & 0xff;
|
|
}
|
|
else
|
|
{
|
|
clocal_r = CLAMP(state->ir >> 12);
|
|
clocal_g = CLAMP(state->ig >> 12);
|
|
clocal_b = CLAMP(state->ib >> 12);
|
|
}
|
|
|
|
switch (_rgb_sel)
|
|
{
|
|
case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/
|
|
cother_r = CLAMP(state->ir >> 12);
|
|
cother_g = CLAMP(state->ig >> 12);
|
|
cother_b = CLAMP(state->ib >> 12);
|
|
break;
|
|
|
|
case CC_LOCALSELECT_TEX: /*TREX Color Output*/
|
|
cother_r = state->tex_r[0];
|
|
cother_g = state->tex_g[0];
|
|
cother_b = state->tex_b[0];
|
|
break;
|
|
|
|
case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/
|
|
cother_r = (params->color1 >> 16) & 0xff;
|
|
cother_g = (params->color1 >> 8) & 0xff;
|
|
cother_b = params->color1 & 0xff;
|
|
break;
|
|
|
|
case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/
|
|
cother_r = src_r;
|
|
cother_g = src_g;
|
|
cother_b = src_b;
|
|
break;
|
|
}
|
|
|
|
switch (cca_localselect)
|
|
{
|
|
case CCA_LOCALSELECT_ITER_A:
|
|
alocal = CLAMP(state->ia >> 12);
|
|
break;
|
|
|
|
case CCA_LOCALSELECT_COLOR0:
|
|
alocal = (params->color0 >> 24) & 0xff;
|
|
break;
|
|
|
|
case CCA_LOCALSELECT_ITER_Z:
|
|
alocal = CLAMP(state->z >> 20);
|
|
break;
|
|
|
|
default:
|
|
fatal("Bad cca_localselect %i\n", cca_localselect);
|
|
alocal = 0xff;
|
|
break;
|
|
}
|
|
|
|
switch (a_sel)
|
|
{
|
|
case A_SEL_ITER_A:
|
|
aother = CLAMP(state->ia >> 12);
|
|
break;
|
|
case A_SEL_TEX:
|
|
aother = state->tex_a[0];
|
|
break;
|
|
case A_SEL_COLOR1:
|
|
aother = (params->color1 >> 24) & 0xff;
|
|
break;
|
|
default:
|
|
fatal("Bad a_sel %i\n", a_sel);
|
|
aother = 0;
|
|
break;
|
|
}
|
|
|
|
if (cc_zero_other)
|
|
{
|
|
src_r = 0;
|
|
src_g = 0;
|
|
src_b = 0;
|
|
}
|
|
else
|
|
{
|
|
src_r = cother_r;
|
|
src_g = cother_g;
|
|
src_b = cother_b;
|
|
}
|
|
|
|
if (cca_zero_other)
|
|
src_a = 0;
|
|
else
|
|
src_a = aother;
|
|
|
|
if (cc_sub_clocal)
|
|
{
|
|
src_r -= clocal_r;
|
|
src_g -= clocal_g;
|
|
src_b -= clocal_b;
|
|
}
|
|
|
|
if (cca_sub_clocal)
|
|
src_a -= alocal;
|
|
|
|
switch (cc_mselect)
|
|
{
|
|
case CC_MSELECT_ZERO:
|
|
msel_r = 0;
|
|
msel_g = 0;
|
|
msel_b = 0;
|
|
break;
|
|
case CC_MSELECT_CLOCAL:
|
|
msel_r = clocal_r;
|
|
msel_g = clocal_g;
|
|
msel_b = clocal_b;
|
|
break;
|
|
case CC_MSELECT_AOTHER:
|
|
msel_r = aother;
|
|
msel_g = aother;
|
|
msel_b = aother;
|
|
break;
|
|
case CC_MSELECT_ALOCAL:
|
|
msel_r = alocal;
|
|
msel_g = alocal;
|
|
msel_b = alocal;
|
|
break;
|
|
case CC_MSELECT_TEX:
|
|
msel_r = state->tex_a[0];
|
|
msel_g = state->tex_a[0];
|
|
msel_b = state->tex_a[0];
|
|
break;
|
|
case CC_MSELECT_TEXRGB:
|
|
msel_r = state->tex_r[0];
|
|
msel_g = state->tex_g[0];
|
|
msel_b = state->tex_b[0];
|
|
break;
|
|
|
|
default:
|
|
fatal("Bad cc_mselect %i\n", cc_mselect);
|
|
msel_r = 0;
|
|
msel_g = 0;
|
|
msel_b = 0;
|
|
break;
|
|
}
|
|
|
|
switch (cca_mselect)
|
|
{
|
|
case CCA_MSELECT_ZERO:
|
|
msel_a = 0;
|
|
break;
|
|
case CCA_MSELECT_ALOCAL:
|
|
msel_a = alocal;
|
|
break;
|
|
case CCA_MSELECT_AOTHER:
|
|
msel_a = aother;
|
|
break;
|
|
case CCA_MSELECT_ALOCAL2:
|
|
msel_a = alocal;
|
|
break;
|
|
case CCA_MSELECT_TEX:
|
|
msel_a = state->tex_a[0];
|
|
break;
|
|
|
|
default:
|
|
fatal("Bad cca_mselect %i\n", cca_mselect);
|
|
msel_a = 0;
|
|
break;
|
|
}
|
|
|
|
if (!cc_reverse_blend)
|
|
{
|
|
msel_r ^= 0xff;
|
|
msel_g ^= 0xff;
|
|
msel_b ^= 0xff;
|
|
}
|
|
msel_r++;
|
|
msel_g++;
|
|
msel_b++;
|
|
|
|
if (!cca_reverse_blend)
|
|
msel_a ^= 0xff;
|
|
msel_a++;
|
|
|
|
src_r = (src_r * msel_r) >> 8;
|
|
src_g = (src_g * msel_g) >> 8;
|
|
src_b = (src_b * msel_b) >> 8;
|
|
src_a = (src_a * msel_a) >> 8;
|
|
|
|
switch (cc_add)
|
|
{
|
|
case CC_ADD_CLOCAL:
|
|
src_r += clocal_r;
|
|
src_g += clocal_g;
|
|
src_b += clocal_b;
|
|
break;
|
|
case CC_ADD_ALOCAL:
|
|
src_r += alocal;
|
|
src_g += alocal;
|
|
src_b += alocal;
|
|
break;
|
|
case 0:
|
|
break;
|
|
default:
|
|
fatal("Bad cc_add %i\n", cc_add);
|
|
}
|
|
|
|
if (cca_add)
|
|
src_a += alocal;
|
|
|
|
src_r = CLAMP(src_r);
|
|
src_g = CLAMP(src_g);
|
|
src_b = CLAMP(src_b);
|
|
src_a = CLAMP(src_a);
|
|
|
|
if (cc_invert_output)
|
|
{
|
|
src_r ^= 0xff;
|
|
src_g ^= 0xff;
|
|
src_b ^= 0xff;
|
|
}
|
|
if (cca_invert_output)
|
|
src_a ^= 0xff;
|
|
|
|
if (params->fogMode & FOG_ENABLE)
|
|
APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w);
|
|
|
|
if (params->alphaMode & 1)
|
|
ALPHA_TEST(src_a);
|
|
|
|
if (params->alphaMode & (1 << 4))
|
|
ALPHA_BLEND(src_r, src_g, src_b, src_a);
|
|
|
|
if (update)
|
|
{
|
|
if (dither)
|
|
{
|
|
if (dither2x2)
|
|
{
|
|
src_r = dither_rb2x2[src_r][real_y & 1][x & 1];
|
|
src_g = dither_g2x2[src_g][real_y & 1][x & 1];
|
|
src_b = dither_rb2x2[src_b][real_y & 1][x & 1];
|
|
}
|
|
else
|
|
{
|
|
src_r = dither_rb[src_r][real_y & 3][x & 3];
|
|
src_g = dither_g[src_g][real_y & 3][x & 3];
|
|
src_b = dither_rb[src_b][real_y & 3][x & 3];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
src_r >>= 3;
|
|
src_g >>= 2;
|
|
src_b >>= 3;
|
|
}
|
|
|
|
if (params->fbzMode & FBZ_RGB_WMASK)
|
|
fb_mem[x] = src_b | (src_g << 5) | (src_r << 11);
|
|
|
|
if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE))
|
|
aux_mem[x] = new_depth;
|
|
}
|
|
}
|
|
voodoo_output &= ~2;
|
|
voodoo->fbiPixelsOut++;
|
|
skip_pixel:
|
|
if (state->xdir > 0)
|
|
{
|
|
state->ir += params->dRdX;
|
|
state->ig += params->dGdX;
|
|
state->ib += params->dBdX;
|
|
state->ia += params->dAdX;
|
|
state->z += params->dZdX;
|
|
state->tmu0_s += params->tmu[0].dSdX;
|
|
state->tmu0_t += params->tmu[0].dTdX;
|
|
state->tmu0_w += params->tmu[0].dWdX;
|
|
state->tmu1_s += params->tmu[1].dSdX;
|
|
state->tmu1_t += params->tmu[1].dTdX;
|
|
state->tmu1_w += params->tmu[1].dWdX;
|
|
state->w += params->dWdX;
|
|
}
|
|
else
|
|
{
|
|
state->ir -= params->dRdX;
|
|
state->ig -= params->dGdX;
|
|
state->ib -= params->dBdX;
|
|
state->ia -= params->dAdX;
|
|
state->z -= params->dZdX;
|
|
state->tmu0_s -= params->tmu[0].dSdX;
|
|
state->tmu0_t -= params->tmu[0].dTdX;
|
|
state->tmu0_w -= params->tmu[0].dWdX;
|
|
state->tmu1_s -= params->tmu[1].dSdX;
|
|
state->tmu1_t -= params->tmu[1].dTdX;
|
|
state->tmu1_w -= params->tmu[1].dWdX;
|
|
state->w -= params->dWdX;
|
|
}
|
|
|
|
x += state->xdir;
|
|
} while (start_x != x2);
|
|
|
|
voodoo->pixel_count[odd_even] += state->pixel_count;
|
|
voodoo->texel_count[odd_even] += state->texel_count;
|
|
voodoo->fbiPixelsIn += state->pixel_count;
|
|
|
|
if (voodoo->params.draw_offset == voodoo->params.front_offset)
|
|
voodoo->dirty_line[real_y] = 1;
|
|
next_line:
|
|
state->base_r += params->dRdY;
|
|
state->base_g += params->dGdY;
|
|
state->base_b += params->dBdY;
|
|
state->base_a += params->dAdY;
|
|
state->base_z += params->dZdY;
|
|
state->tmu[0].base_s += params->tmu[0].dSdY;
|
|
state->tmu[0].base_t += params->tmu[0].dTdY;
|
|
state->tmu[0].base_w += params->tmu[0].dWdY;
|
|
state->tmu[1].base_s += params->tmu[1].dSdY;
|
|
state->tmu[1].base_t += params->tmu[1].dTdY;
|
|
state->tmu[1].base_w += params->tmu[1].dWdY;
|
|
state->base_w += params->dWdY;
|
|
state->xstart += state->dx1;
|
|
state->xend += state->dx2;
|
|
}
|
|
|
|
voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++;
|
|
voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++;
|
|
}
|
|
|
|
static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even)
|
|
{
|
|
voodoo_state_t state;
|
|
int vertexAy_adjusted;
|
|
int vertexBy_adjusted;
|
|
int vertexCy_adjusted;
|
|
int dx, dy;
|
|
|
|
uint64_t tempdx, tempdy;
|
|
uint64_t tempLOD;
|
|
int LOD;
|
|
int lodbias;
|
|
|
|
voodoo->tri_count++;
|
|
|
|
dx = 8 - (params->vertexAx & 0xf);
|
|
if ((params->vertexAx & 0xf) > 8)
|
|
dx += 16;
|
|
dy = 8 - (params->vertexAy & 0xf);
|
|
if ((params->vertexAy & 0xf) > 8)
|
|
dy += 16;
|
|
|
|
/* pclog("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0,
|
|
(float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0,
|
|
(float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0,
|
|
(params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0,
|
|
(params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/
|
|
|
|
state.base_r = params->startR;
|
|
state.base_g = params->startG;
|
|
state.base_b = params->startB;
|
|
state.base_a = params->startA;
|
|
state.base_z = params->startZ;
|
|
state.tmu[0].base_s = params->tmu[0].startS;
|
|
state.tmu[0].base_t = params->tmu[0].startT;
|
|
state.tmu[0].base_w = params->tmu[0].startW;
|
|
state.tmu[1].base_s = params->tmu[1].startS;
|
|
state.tmu[1].base_t = params->tmu[1].startT;
|
|
state.tmu[1].base_w = params->tmu[1].startW;
|
|
state.base_w = params->startW;
|
|
|
|
if (params->fbzColorPath & FBZ_PARAM_ADJUST)
|
|
{
|
|
state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4;
|
|
state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4;
|
|
state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4;
|
|
state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4;
|
|
state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4;
|
|
state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4;
|
|
state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4;
|
|
state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4;
|
|
state.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4;
|
|
state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4;
|
|
state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].dWdY) >> 4;
|
|
state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4;
|
|
}
|
|
|
|
tris++;
|
|
|
|
state.vertexAy = params->vertexAy & ~0xffff0000;
|
|
if (state.vertexAy & 0x8000)
|
|
state.vertexAy |= 0xffff0000;
|
|
state.vertexBy = params->vertexBy & ~0xffff0000;
|
|
if (state.vertexBy & 0x8000)
|
|
state.vertexBy |= 0xffff0000;
|
|
state.vertexCy = params->vertexCy & ~0xffff0000;
|
|
if (state.vertexCy & 0x8000)
|
|
state.vertexCy |= 0xffff0000;
|
|
|
|
state.vertexAx = params->vertexAx & ~0xffff0000;
|
|
if (state.vertexAx & 0x8000)
|
|
state.vertexAx |= 0xffff0000;
|
|
state.vertexBx = params->vertexBx & ~0xffff0000;
|
|
if (state.vertexBx & 0x8000)
|
|
state.vertexBx |= 0xffff0000;
|
|
state.vertexCx = params->vertexCx & ~0xffff0000;
|
|
if (state.vertexCx & 0x8000)
|
|
state.vertexCx |= 0xffff0000;
|
|
|
|
vertexAy_adjusted = (state.vertexAy+7) >> 4;
|
|
vertexBy_adjusted = (state.vertexBy+7) >> 4;
|
|
vertexCy_adjusted = (state.vertexCy+7) >> 4;
|
|
|
|
if (state.vertexBy - state.vertexAy)
|
|
state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy);
|
|
else
|
|
state.dxAB = 0;
|
|
if (state.vertexCy - state.vertexAy)
|
|
state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy);
|
|
else
|
|
state.dxAC = 0;
|
|
if (state.vertexCy - state.vertexBy)
|
|
state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy);
|
|
else
|
|
state.dxBC = 0;
|
|
|
|
state.lod_min[0] = (params->tLOD[0] & 0x3f) << 6;
|
|
state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6;
|
|
if (state.lod_max[0] > 0x800)
|
|
state.lod_max[0] = 0x800;
|
|
state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6;
|
|
state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6;
|
|
if (state.lod_max[1] > 0x800)
|
|
state.lod_max[1] = 0x800;
|
|
|
|
state.xstart = state.xend = state.vertexAx << 8;
|
|
state.xdir = params->sign ? -1 : 1;
|
|
|
|
state.y = (state.vertexAy + 8) >> 4;
|
|
state.ydir = 1;
|
|
|
|
|
|
tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14);
|
|
tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14);
|
|
|
|
if (tempdx > tempdy)
|
|
tempLOD = tempdx;
|
|
else
|
|
tempLOD = tempdy;
|
|
|
|
LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256);
|
|
LOD >>= 2;
|
|
|
|
lodbias = (params->tLOD[0] >> 12) & 0x3f;
|
|
if (lodbias & 0x20)
|
|
lodbias |= ~0x3f;
|
|
state.tmu[0].lod = LOD + (lodbias << 6);
|
|
|
|
|
|
tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14);
|
|
tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14);
|
|
|
|
if (tempdx > tempdy)
|
|
tempLOD = tempdx;
|
|
else
|
|
tempLOD = tempdy;
|
|
|
|
LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256);
|
|
LOD >>= 2;
|
|
|
|
lodbias = (params->tLOD[1] >> 12) & 0x3f;
|
|
if (lodbias & 0x20)
|
|
lodbias |= ~0x3f;
|
|
state.tmu[1].lod = LOD + (lodbias << 6);
|
|
|
|
|
|
voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even);
|
|
}
|
|
|
|
static inline void wake_render_thread(voodoo_t *voodoo)
|
|
{
|
|
thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/
|
|
if (voodoo->render_threads == 2)
|
|
thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/
|
|
}
|
|
|
|
static inline void wait_for_render_thread_idle(voodoo_t *voodoo)
|
|
{
|
|
while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1]))
|
|
{
|
|
wake_render_thread(voodoo);
|
|
if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0])
|
|
thread_wait_event(voodoo->render_not_full_event[0], 1);
|
|
if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1]))
|
|
thread_wait_event(voodoo->render_not_full_event[1], 1);
|
|
}
|
|
}
|
|
|
|
static void render_thread(void *param, int odd_even)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)param;
|
|
|
|
while (1)
|
|
{
|
|
thread_set_event(voodoo->render_not_full_event[odd_even]);
|
|
thread_wait_event(voodoo->wake_render_thread[odd_even], -1);
|
|
thread_reset_event(voodoo->wake_render_thread[odd_even]);
|
|
voodoo->render_voodoo_busy[odd_even] = 1;
|
|
|
|
while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1))
|
|
{
|
|
uint64_t start_time = timer_read();
|
|
uint64_t end_time;
|
|
voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK];
|
|
|
|
voodoo_triangle(voodoo, params, odd_even);
|
|
|
|
voodoo->params_read_idx[odd_even]++;
|
|
|
|
if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10))
|
|
thread_set_event(voodoo->render_not_full_event[odd_even]);
|
|
|
|
end_time = timer_read();
|
|
voodoo_render_time[odd_even] += end_time - start_time;
|
|
}
|
|
|
|
voodoo->render_voodoo_busy[odd_even] = 0;
|
|
}
|
|
}
|
|
|
|
static void render_thread_1(void *param)
|
|
{
|
|
render_thread(param, 0);
|
|
}
|
|
static void render_thread_2(void *param)
|
|
{
|
|
render_thread(param, 1);
|
|
}
|
|
|
|
static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params)
|
|
{
|
|
voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK];
|
|
|
|
while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2))
|
|
{
|
|
thread_reset_event(voodoo->render_not_full_event[0]);
|
|
if (voodoo->render_threads == 2)
|
|
thread_reset_event(voodoo->render_not_full_event[1]);
|
|
if (PARAM_FULL_1)
|
|
{
|
|
thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/
|
|
}
|
|
if (voodoo->render_threads == 2 && PARAM_FULL_2)
|
|
{
|
|
thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/
|
|
}
|
|
}
|
|
|
|
use_texture(voodoo, params, 0);
|
|
if (voodoo->dual_tmus)
|
|
use_texture(voodoo, params, 1);
|
|
|
|
memcpy(params_new, params, sizeof(voodoo_params_t));
|
|
|
|
voodoo->params_write_idx++;
|
|
|
|
if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4))
|
|
wake_render_thread(voodoo);
|
|
}
|
|
|
|
static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params)
|
|
{
|
|
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);
|
|
|
|
for (y = low_y; y < high_y; y++)
|
|
{
|
|
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)
|
|
{
|
|
for (y = low_y; y < high_y; y++)
|
|
{
|
|
uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask];
|
|
int x;
|
|
|
|
for (x = params->clipLeft; x < params->clipRight; x++)
|
|
abuf[x] = params->zaColor & 0xffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
};
|
|
|
|
static void triangle_setup(voodoo_t *voodoo)
|
|
{
|
|
float dxAB, dxBC, dyAB, dyBC;
|
|
float area;
|
|
int va = 0, vb = 1, vc = 2;
|
|
int reverse_cull = 0;
|
|
|
|
if (voodoo->verts[0].sVy < voodoo->verts[1].sVy)
|
|
{
|
|
if (voodoo->verts[1].sVy < voodoo->verts[2].sVy)
|
|
{
|
|
/* V1>V0, V2>V1, V2>V1>V0*/
|
|
va = 0; /*OK*/
|
|
vb = 1;
|
|
vc = 2;
|
|
}
|
|
else
|
|
{
|
|
/* V1>V0, V1>V2*/
|
|
if (voodoo->verts[0].sVy < voodoo->verts[2].sVy)
|
|
{
|
|
/* V1>V0, V1>V2, V2>V0, V1>V2>V0*/
|
|
va = 0;
|
|
vb = 2;
|
|
vc = 1;
|
|
reverse_cull = 1;
|
|
}
|
|
else
|
|
{
|
|
/* V1>V0, V1>V2, V0>V2, V1>V0>V2*/
|
|
va = 2;
|
|
vb = 0;
|
|
vc = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (voodoo->verts[1].sVy < voodoo->verts[2].sVy)
|
|
{
|
|
/* V0>V1, V2>V1*/
|
|
if (voodoo->verts[0].sVy < voodoo->verts[2].sVy)
|
|
{
|
|
/* V0>V1, V2>V1, V2>V0, V2>V0>V1*/
|
|
va = 1;
|
|
vb = 0;
|
|
vc = 2;
|
|
reverse_cull = 1;
|
|
}
|
|
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;
|
|
reverse_cull = 1;
|
|
}
|
|
}
|
|
|
|
dxAB = voodoo->verts[va].sVx - voodoo->verts[vb].sVx;
|
|
dxBC = voodoo->verts[vb].sVx - voodoo->verts[vc].sVx;
|
|
dyAB = voodoo->verts[va].sVy - voodoo->verts[vb].sVy;
|
|
dyBC = voodoo->verts[vb].sVy - voodoo->verts[vc].sVy;
|
|
|
|
area = dxAB * dyBC - dxBC * dyAB;
|
|
|
|
if (area == 0.0)
|
|
{
|
|
if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) &&
|
|
!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG))
|
|
voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN;
|
|
|
|
return;
|
|
}
|
|
|
|
dxAB /= area;
|
|
dxBC /= area;
|
|
dyAB /= area;
|
|
dyBC /= area;
|
|
|
|
if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE)
|
|
{
|
|
int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN;
|
|
int sign = (area < 0.0);
|
|
|
|
if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG))
|
|
voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN;
|
|
|
|
if (reverse_cull)
|
|
sign = !sign;
|
|
|
|
if (cull_sign && sign)
|
|
return;
|
|
if (!cull_sign && !sign)
|
|
return;
|
|
}
|
|
|
|
voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVy * 16.0f) & 0xffff);
|
|
voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVy * 16.0f) & 0xffff);
|
|
voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVx * 16.0f) & 0xffff);
|
|
voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVy * 16.0f) & 0xffff);
|
|
|
|
if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy)
|
|
fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy);
|
|
|
|
if (voodoo->sSetupMode & SETUPMODE_RGB)
|
|
{
|
|
voodoo->params.startR = (int32_t)(voodoo->verts[va].sRed * 4096.0f);
|
|
voodoo->params.dRdX = (int32_t)(((voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dyBC - (voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dyAB) * 4096.0f);
|
|
voodoo->params.dRdY = (int32_t)(((voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dxAB - (voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dxBC) * 4096.0f);
|
|
voodoo->params.startG = (int32_t)(voodoo->verts[va].sGreen * 4096.0f);
|
|
voodoo->params.dGdX = (int32_t)(((voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dyBC - (voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dyAB) * 4096.0f);
|
|
voodoo->params.dGdY = (int32_t)(((voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dxAB - (voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dxBC) * 4096.0f);
|
|
voodoo->params.startB = (int32_t)(voodoo->verts[va].sBlue * 4096.0f);
|
|
voodoo->params.dBdX = (int32_t)(((voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dyBC - (voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dyAB) * 4096.0f);
|
|
voodoo->params.dBdY = (int32_t)(((voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dxAB - (voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_ALPHA)
|
|
{
|
|
voodoo->params.startA = (int32_t)(voodoo->verts[va].sAlpha * 4096.0f);
|
|
voodoo->params.dAdX = (int32_t)(((voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dyBC - (voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dyAB) * 4096.0f);
|
|
voodoo->params.dAdY = (int32_t)(((voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dxAB - (voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_Z)
|
|
{
|
|
voodoo->params.startZ = (int32_t)(voodoo->verts[va].sVz * 4096.0f);
|
|
voodoo->params.dZdX = (int32_t)(((voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dyBC - (voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dyAB) * 4096.0f);
|
|
voodoo->params.dZdY = (int32_t)(((voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dxAB - (voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dxBC) * 4096.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_Wb)
|
|
{
|
|
voodoo->params.startW = (int64_t)(voodoo->verts[va].sWb * 4294967296.0f);
|
|
voodoo->params.dWdX = (int64_t)(((voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dyBC - (voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dyAB) * 4294967296.0f);
|
|
voodoo->params.dWdY = (int64_t)(((voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dxAB - (voodoo->verts[va].sWb - voodoo->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)(voodoo->verts[va].sW0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->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)(voodoo->verts[va].sS0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dSdX = (int64_t)(((voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dyBC - (voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dSdY = (int64_t)(((voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dxAB - (voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[0].startT = (int64_t)(voodoo->verts[va].sT0 * 4294967296.0f);
|
|
voodoo->params.tmu[0].dTdX = (int64_t)(((voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dyBC - (voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[0].dTdY = (int64_t)(((voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dxAB - (voodoo->verts[va].sT0 - voodoo->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)(voodoo->verts[va].sW1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f);
|
|
}
|
|
if (voodoo->sSetupMode & SETUPMODE_S1_T1)
|
|
{
|
|
voodoo->params.tmu[1].startS = (int64_t)(voodoo->verts[va].sS1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dSdX = (int64_t)(((voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dyBC - (voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dSdY = (int64_t)(((voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dxAB - (voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dxBC) * 4294967296.0f);
|
|
voodoo->params.tmu[1].startT = (int64_t)(voodoo->verts[va].sT1 * 4294967296.0f);
|
|
voodoo->params.tmu[1].dTdX = (int64_t)(((voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dyBC - (voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dyAB) * 4294967296.0f);
|
|
voodoo->params.tmu[1].dTdY = (int64_t)(((voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dxAB - (voodoo->verts[va].sT1 - voodoo->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;
|
|
|
|
queue_triangle(voodoo, &voodoo->params);
|
|
}
|
|
|
|
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; \
|
|
}
|
|
|
|
#define ABS(x) ((x) > 0 ? (x) : -(x))
|
|
|
|
static void 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 src_x, 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);*/
|
|
|
|
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 = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride];
|
|
int dst_x = voodoo->bltDstX;
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void blit_data(voodoo_t *voodoo, uint32_t data)
|
|
{
|
|
uint32_t data_orig = data;
|
|
int src_bits = 32;
|
|
uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8);
|
|
uint16_t *dst = (uint16_t *)&voodoo->fb_mem[base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride];
|
|
|
|
if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN)
|
|
return;
|
|
|
|
while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x)
|
|
{
|
|
int r, g, b;
|
|
uint16_t src_dat, 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 (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;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum
|
|
{
|
|
CHIP_FBI = 0x1,
|
|
CHIP_TREX0 = 0x2,
|
|
CHIP_TREX1 = 0x4,
|
|
CHIP_TREX2 = 0x8
|
|
};
|
|
|
|
static void 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);
|
|
if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES == 65536)
|
|
{
|
|
/*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/
|
|
memset(voodoo->dirty_line, 1, 1024);
|
|
voodoo->front_offset = voodoo->params.front_offset;
|
|
voodoo->swap_count--;
|
|
voodoo->swap_pending = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
union
|
|
{
|
|
uint32_t i;
|
|
float f;
|
|
} tempif;
|
|
int ad21 = addr & (1 << 21);
|
|
int chip = (addr >> 10) & 0xf;
|
|
if (!chip)
|
|
chip = 0xf;
|
|
|
|
tempif.i = val;
|
|
//pclog("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip);
|
|
addr &= 0x3fc;
|
|
|
|
if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21)
|
|
addr |= 0x400;
|
|
switch (addr)
|
|
{
|
|
case SST_swapbufferCMD:
|
|
// pclog(" start swap buffer command\n");
|
|
|
|
if (TRIPLE_BUFFER)
|
|
{
|
|
voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3;
|
|
voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3;
|
|
}
|
|
else
|
|
{
|
|
voodoo->disp_buffer = !voodoo->disp_buffer;
|
|
voodoo->draw_buffer = !voodoo->draw_buffer;
|
|
}
|
|
voodoo_recalc(voodoo);
|
|
|
|
voodoo->params.swapbufferCMD = val;
|
|
|
|
pclog("Swap buffer %08x %d %p\n", val, voodoo->swap_count, &voodoo->swap_count);
|
|
// voodoo->front_offset = params->front_offset;
|
|
wait_for_render_thread_idle(voodoo);
|
|
if (!(val & 1))
|
|
{
|
|
memset(voodoo->dirty_line, 1, 1024);
|
|
voodoo->front_offset = voodoo->params.front_offset;
|
|
voodoo->swap_count--;
|
|
}
|
|
else if (TRIPLE_BUFFER)
|
|
{
|
|
if (voodoo->swap_pending)
|
|
wait_for_swap_complete(voodoo);
|
|
|
|
voodoo->swap_interval = (val >> 1) & 0xff;
|
|
voodoo->swap_offset = voodoo->params.front_offset;
|
|
voodoo->swap_pending = 1;
|
|
}
|
|
else
|
|
{
|
|
voodoo->swap_interval = (val >> 1) & 0xff;
|
|
voodoo->swap_offset = voodoo->params.front_offset;
|
|
voodoo->swap_pending = 1;
|
|
|
|
wait_for_swap_complete(voodoo);
|
|
}
|
|
voodoo->cmd_read++;
|
|
break;
|
|
|
|
case SST_vertexAx: case SST_remap_vertexAx:
|
|
voodoo->params.vertexAx = val & 0xffff;
|
|
break;
|
|
case SST_vertexAy: case SST_remap_vertexAy:
|
|
voodoo->params.vertexAy = val & 0xffff;
|
|
break;
|
|
case SST_vertexBx: case SST_remap_vertexBx:
|
|
voodoo->params.vertexBx = val & 0xffff;
|
|
break;
|
|
case SST_vertexBy: case SST_remap_vertexBy:
|
|
voodoo->params.vertexBy = val & 0xffff;
|
|
break;
|
|
case SST_vertexCx: case SST_remap_vertexCx:
|
|
voodoo->params.vertexCx = val & 0xffff;
|
|
break;
|
|
case SST_vertexCy: case SST_remap_vertexCy:
|
|
voodoo->params.vertexCy = val & 0xffff;
|
|
break;
|
|
|
|
case SST_startR: case SST_remap_startR:
|
|
voodoo->params.startR = val & 0xffffff;
|
|
break;
|
|
case SST_startG: case SST_remap_startG:
|
|
voodoo->params.startG = val & 0xffffff;
|
|
break;
|
|
case SST_startB: case SST_remap_startB:
|
|
voodoo->params.startB = val & 0xffffff;
|
|
break;
|
|
case SST_startZ: case SST_remap_startZ:
|
|
voodoo->params.startZ = val;
|
|
break;
|
|
case SST_startA: case SST_remap_startA:
|
|
voodoo->params.startA = val & 0xffffff;
|
|
break;
|
|
case SST_startS: case SST_remap_startS:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_startT: case SST_remap_startT:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_startW: case SST_remap_startW:
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.startW = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2;
|
|
break;
|
|
|
|
case SST_dRdX: case SST_remap_dRdX:
|
|
voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dGdX: case SST_remap_dGdX:
|
|
voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dBdX: case SST_remap_dBdX:
|
|
voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dZdX: case SST_remap_dZdX:
|
|
voodoo->params.dZdX = val;
|
|
break;
|
|
case SST_dAdX: case SST_remap_dAdX:
|
|
voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dSdX: case SST_remap_dSdX:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_dTdX: case SST_remap_dTdX:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_dWdX: case SST_remap_dWdX:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.dWdX = (int64_t)(int32_t)val << 2;
|
|
break;
|
|
|
|
case SST_dRdY: case SST_remap_dRdY:
|
|
voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dGdY: case SST_remap_dGdY:
|
|
voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dBdY: case SST_remap_dBdY:
|
|
voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dZdY: case SST_remap_dZdY:
|
|
voodoo->params.dZdY = val;
|
|
break;
|
|
case SST_dAdY: case SST_remap_dAdY:
|
|
voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0);
|
|
break;
|
|
case SST_dSdY: case SST_remap_dSdY:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_dTdY: case SST_remap_dTdY:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14;
|
|
break;
|
|
case SST_dWdY: case SST_remap_dWdY:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2;
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.dWdY = (int64_t)(int32_t)val << 2;
|
|
break;
|
|
|
|
case SST_triangleCMD: case SST_remap_triangleCMD:
|
|
voodoo->params.sign = val & (1 << 31);
|
|
|
|
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;
|
|
|
|
queue_triangle(voodoo, &voodoo->params);
|
|
|
|
voodoo->cmd_read++;
|
|
break;
|
|
|
|
case SST_fvertexAx: case SST_remap_fvertexAx:
|
|
voodoo->fvertexAx.i = val;
|
|
voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff;
|
|
break;
|
|
case SST_fvertexAy: case SST_remap_fvertexAy:
|
|
voodoo->fvertexAy.i = val;
|
|
voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff;
|
|
break;
|
|
case SST_fvertexBx: case SST_remap_fvertexBx:
|
|
voodoo->fvertexBx.i = val;
|
|
voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff;
|
|
break;
|
|
case SST_fvertexBy: case SST_remap_fvertexBy:
|
|
voodoo->fvertexBy.i = val;
|
|
voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff;
|
|
break;
|
|
case SST_fvertexCx: case SST_remap_fvertexCx:
|
|
voodoo->fvertexCx.i = val;
|
|
voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff;
|
|
break;
|
|
case SST_fvertexCy: case SST_remap_fvertexCy:
|
|
voodoo->fvertexCy.i = val;
|
|
voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff;
|
|
break;
|
|
|
|
case SST_fstartR: case SST_remap_fstartR:
|
|
tempif.i = val;
|
|
voodoo->params.startR = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fstartG: case SST_remap_fstartG:
|
|
tempif.i = val;
|
|
voodoo->params.startG = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fstartB: case SST_remap_fstartB:
|
|
tempif.i = val;
|
|
voodoo->params.startB = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fstartZ: case SST_remap_fstartZ:
|
|
tempif.i = val;
|
|
voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fstartA: case SST_remap_fstartA:
|
|
tempif.i = val;
|
|
voodoo->params.startA = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fstartS: case SST_remap_fstartS:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fstartT: case SST_remap_fstartT:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fstartW: case SST_remap_fstartW:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
|
|
case SST_fdRdX: case SST_remap_fdRdX:
|
|
tempif.i = val;
|
|
voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdGdX: case SST_remap_fdGdX:
|
|
tempif.i = val;
|
|
voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdBdX: case SST_remap_fdBdX:
|
|
tempif.i = val;
|
|
voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdZdX: case SST_remap_fdZdX:
|
|
tempif.i = val;
|
|
voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdAdX: case SST_remap_fdAdX:
|
|
tempif.i = val;
|
|
voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdSdX: case SST_remap_fdSdX:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fdTdX: case SST_remap_fdTdX:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fdWdX: case SST_remap_fdWdX:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
|
|
case SST_fdRdY: case SST_remap_fdRdY:
|
|
tempif.i = val;
|
|
voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdGdY: case SST_remap_fdGdY:
|
|
tempif.i = val;
|
|
voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdBdY: case SST_remap_fdBdY:
|
|
tempif.i = val;
|
|
voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdZdY: case SST_remap_fdZdY:
|
|
tempif.i = val;
|
|
voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdAdY: case SST_remap_fdAdY:
|
|
tempif.i = val;
|
|
voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f);
|
|
break;
|
|
case SST_fdSdY: case SST_remap_fdSdY:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fdTdY: case SST_remap_fdTdY:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
case SST_fdWdY: case SST_remap_fdWdY:
|
|
tempif.i = val;
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
if (chip & CHIP_FBI)
|
|
voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f);
|
|
break;
|
|
|
|
case SST_ftriangleCMD:
|
|
voodoo->params.sign = val & (1 << 31);
|
|
|
|
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;
|
|
|
|
queue_triangle(voodoo, &voodoo->params);
|
|
|
|
voodoo->cmd_read++;
|
|
break;
|
|
|
|
case SST_fbzColorPath:
|
|
voodoo->params.fbzColorPath = val;
|
|
voodoo->rgb_sel = val & 3;
|
|
break;
|
|
|
|
case SST_fogMode:
|
|
voodoo->params.fogMode = val;
|
|
break;
|
|
case SST_alphaMode:
|
|
voodoo->params.alphaMode = val;
|
|
break;
|
|
case SST_fbzMode:
|
|
voodoo->params.fbzMode = val;
|
|
voodoo_recalc(voodoo);
|
|
break;
|
|
case SST_lfbMode:
|
|
voodoo->lfbMode = val;
|
|
voodoo_recalc(voodoo);
|
|
break;
|
|
|
|
case SST_clipLeftRight:
|
|
if (voodoo->type >= VOODOO_2)
|
|
{
|
|
voodoo->params.clipRight = val & 0xfff;
|
|
voodoo->params.clipLeft = (val >> 16) & 0xfff;
|
|
}
|
|
else
|
|
{
|
|
voodoo->params.clipRight = val & 0x3ff;
|
|
voodoo->params.clipLeft = (val >> 16) & 0x3ff;
|
|
}
|
|
break;
|
|
case SST_clipLowYHighY:
|
|
if (voodoo->type >= VOODOO_2)
|
|
{
|
|
voodoo->params.clipHighY = val & 0xfff;
|
|
voodoo->params.clipLowY = (val >> 16) & 0xfff;
|
|
}
|
|
else
|
|
{
|
|
voodoo->params.clipHighY = val & 0x3ff;
|
|
voodoo->params.clipLowY = (val >> 16) & 0x3ff;
|
|
}
|
|
break;
|
|
|
|
case SST_nopCMD:
|
|
voodoo->cmd_read++;
|
|
voodoo->fbiPixelsIn = 0;
|
|
voodoo->fbiChromaFail = 0;
|
|
voodoo->fbiZFuncFail = 0;
|
|
voodoo->fbiAFuncFail = 0;
|
|
voodoo->fbiPixelsOut = 0;
|
|
break;
|
|
case SST_fastfillCMD:
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo_fastfill(voodoo, &voodoo->params);
|
|
voodoo->cmd_read++;
|
|
break;
|
|
|
|
case SST_fogColor:
|
|
voodoo->params.fogColor.r = (val >> 16) & 0xff;
|
|
voodoo->params.fogColor.g = (val >> 8) & 0xff;
|
|
voodoo->params.fogColor.b = val & 0xff;
|
|
break;
|
|
|
|
case SST_zaColor:
|
|
voodoo->params.zaColor = val;
|
|
break;
|
|
case SST_chromaKey:
|
|
voodoo->params.chromaKey_r = (val >> 16) & 0xff;
|
|
voodoo->params.chromaKey_g = (val >> 8) & 0xff;
|
|
voodoo->params.chromaKey_b = val & 0xff;
|
|
voodoo->params.chromaKey = val & 0xffffff;
|
|
break;
|
|
case SST_stipple:
|
|
voodoo->params.stipple = val;
|
|
break;
|
|
case SST_color0:
|
|
voodoo->params.color0 = val;
|
|
break;
|
|
case SST_color1:
|
|
voodoo->params.color1 = val;
|
|
break;
|
|
|
|
case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03:
|
|
case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07:
|
|
case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b:
|
|
case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f:
|
|
case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13:
|
|
case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17:
|
|
case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b:
|
|
case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f:
|
|
addr = (addr - SST_fogTable00) >> 1;
|
|
voodoo->params.fogTable[addr].dfog = val & 0xff;
|
|
voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff;
|
|
voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff;
|
|
voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff;
|
|
break;
|
|
|
|
case SST_clutData:
|
|
voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff;
|
|
voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff;
|
|
voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff;
|
|
if (val & 0x20000000)
|
|
{
|
|
voodoo->clutData[(val >> 24) & 0x3f].b = 255;
|
|
voodoo->clutData[(val >> 24) & 0x3f].g = 255;
|
|
voodoo->clutData[(val >> 24) & 0x3f].r = 255;
|
|
}
|
|
voodoo->clutData_dirty = 1;
|
|
break;
|
|
|
|
case SST_sSetupMode:
|
|
voodoo->sSetupMode = val;
|
|
break;
|
|
case SST_sVx:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sVx = tempif.f;
|
|
// pclog("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f);
|
|
break;
|
|
case SST_sVy:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sVy = tempif.f;
|
|
// pclog("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f);
|
|
break;
|
|
case SST_sARGB:
|
|
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);
|
|
break;
|
|
case SST_sRed:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sRed = tempif.f;
|
|
break;
|
|
case SST_sGreen:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sGreen = tempif.f;
|
|
break;
|
|
case SST_sBlue:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sBlue = tempif.f;
|
|
break;
|
|
case SST_sAlpha:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sAlpha = tempif.f;
|
|
break;
|
|
case SST_sVz:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sVz = tempif.f;
|
|
break;
|
|
case SST_sWb:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sWb = tempif.f;
|
|
break;
|
|
case SST_sW0:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sW0 = tempif.f;
|
|
break;
|
|
case SST_sS0:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sS0 = tempif.f;
|
|
break;
|
|
case SST_sT0:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sT0 = tempif.f;
|
|
break;
|
|
case SST_sW1:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sW1 = tempif.f;
|
|
break;
|
|
case SST_sS1:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sS1 = tempif.f;
|
|
break;
|
|
case SST_sT1:
|
|
tempif.i = val;
|
|
voodoo->verts[3].sT1 = tempif.f;
|
|
break;
|
|
|
|
case SST_sBeginTriCMD:
|
|
// pclog("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx);
|
|
voodoo->verts[0] = voodoo->verts[3];
|
|
voodoo->vertex_num = 1;
|
|
voodoo->num_verticies = 1;
|
|
break;
|
|
case SST_sDrawTriCMD:
|
|
// pclog("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE);
|
|
if (voodoo->vertex_num == 3)
|
|
voodoo->vertex_num = (voodoo->sSetupMode & SETUPMODE_STRIP_MODE) ? 1 : 0;
|
|
voodoo->verts[voodoo->vertex_num] = voodoo->verts[3];
|
|
|
|
voodoo->num_verticies++;
|
|
voodoo->vertex_num++;
|
|
if (voodoo->num_verticies == 3)
|
|
{
|
|
// pclog("triangle_setup\n");
|
|
triangle_setup(voodoo);
|
|
|
|
voodoo->num_verticies = 2;
|
|
}
|
|
if (voodoo->vertex_num == 4)
|
|
fatal("sDrawTriCMD overflow\n");
|
|
break;
|
|
|
|
case SST_bltSrcBaseAddr:
|
|
voodoo->bltSrcBaseAddr = val & 0x3fffff;
|
|
break;
|
|
case SST_bltDstBaseAddr:
|
|
// pclog("Write bltDstBaseAddr %08x\n", val);
|
|
voodoo->bltDstBaseAddr = val & 0x3fffff;
|
|
break;
|
|
case SST_bltXYStrides:
|
|
voodoo->bltSrcXYStride = val & 0xfff;
|
|
voodoo->bltDstXYStride = (val >> 16) & 0xfff;
|
|
// pclog("Write bltXYStrides %08x\n", val);
|
|
break;
|
|
case SST_bltSrcChromaRange:
|
|
voodoo->bltSrcChromaRange = val;
|
|
voodoo->bltSrcChromaMinB = val & 0x1f;
|
|
voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f;
|
|
voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f;
|
|
voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f;
|
|
voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f;
|
|
voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f;
|
|
break;
|
|
case SST_bltDstChromaRange:
|
|
voodoo->bltDstChromaRange = val;
|
|
voodoo->bltDstChromaMinB = val & 0x1f;
|
|
voodoo->bltDstChromaMinG = (val >> 5) & 0x3f;
|
|
voodoo->bltDstChromaMinR = (val >> 11) & 0x1f;
|
|
voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f;
|
|
voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f;
|
|
voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f;
|
|
break;
|
|
case SST_bltClipX:
|
|
voodoo->bltClipRight = val & 0xfff;
|
|
voodoo->bltClipLeft = (val >> 16) & 0xfff;
|
|
break;
|
|
case SST_bltClipY:
|
|
voodoo->bltClipHighY = val & 0xfff;
|
|
voodoo->bltClipLowY = (val >> 16) & 0xfff;
|
|
break;
|
|
|
|
case SST_bltSrcXY:
|
|
voodoo->bltSrcX = val & 0x7ff;
|
|
voodoo->bltSrcY = (val >> 16) & 0x7ff;
|
|
break;
|
|
case SST_bltDstXY:
|
|
// pclog("Write bltDstXY %08x\n", val);
|
|
voodoo->bltDstX = val & 0x7ff;
|
|
voodoo->bltDstY = (val >> 16) & 0x7ff;
|
|
if (val & (1 << 31))
|
|
blit_start(voodoo);
|
|
break;
|
|
case SST_bltSize:
|
|
// pclog("Write bltSize %08x\n", val);
|
|
voodoo->bltSizeX = val & 0xfff;
|
|
if (voodoo->bltSizeX & 0x800)
|
|
voodoo->bltSizeX |= 0xfffff000;
|
|
voodoo->bltSizeY = (val >> 16) & 0xfff;
|
|
if (voodoo->bltSizeY & 0x800)
|
|
voodoo->bltSizeY |= 0xfffff000;
|
|
if (val & (1 << 31))
|
|
blit_start(voodoo);
|
|
break;
|
|
case SST_bltRop:
|
|
voodoo->bltRop[0] = val & 0xf;
|
|
voodoo->bltRop[1] = (val >> 4) & 0xf;
|
|
voodoo->bltRop[2] = (val >> 8) & 0xf;
|
|
voodoo->bltRop[3] = (val >> 12) & 0xf;
|
|
break;
|
|
case SST_bltColor:
|
|
// pclog("Write bltColor %08x\n", val);
|
|
voodoo->bltColorFg = val & 0xffff;
|
|
voodoo->bltColorBg = (val >> 16) & 0xffff;
|
|
break;
|
|
|
|
case SST_bltCommand:
|
|
voodoo->bltCommand = val;
|
|
// pclog("Write bltCommand %08x\n", val);
|
|
if (val & (1 << 31))
|
|
blit_start(voodoo);
|
|
break;
|
|
case SST_bltData:
|
|
blit_data(voodoo, val);
|
|
break;
|
|
|
|
case SST_textureMode:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.textureMode[0] = val;
|
|
voodoo->params.tformat[0] = (val >> 8) & 0xf;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.textureMode[1] = val;
|
|
voodoo->params.tformat[1] = (val >> 8) & 0xf;
|
|
}
|
|
break;
|
|
case SST_tLOD:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.tLOD[0] = val;
|
|
voodoo_recalc_tex(voodoo, 0);
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.tLOD[1] = val;
|
|
voodoo_recalc_tex(voodoo, 1);
|
|
}
|
|
break;
|
|
case SST_tDetail:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.detail_max[0] = val & 0xff;
|
|
voodoo->params.detail_bias[0] = (val >> 8) & 0x3f;
|
|
voodoo->params.detail_scale[0] = (val >> 14) & 7;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.detail_max[1] = val & 0xff;
|
|
voodoo->params.detail_bias[1] = (val >> 8) & 0x3f;
|
|
voodoo->params.detail_scale[1] = (val >> 14) & 7;
|
|
}
|
|
break;
|
|
case SST_texBaseAddr:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 0);
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 1);
|
|
}
|
|
break;
|
|
case SST_texBaseAddr1:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 0);
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 1);
|
|
}
|
|
break;
|
|
case SST_texBaseAddr2:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 0);
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 1);
|
|
}
|
|
break;
|
|
case SST_texBaseAddr38:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 0);
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3;
|
|
voodoo_recalc_tex(voodoo, 1);
|
|
}
|
|
break;
|
|
|
|
case SST_trexInit1:
|
|
if (chip & CHIP_TREX0)
|
|
voodoo->trexInit1[0] = val;
|
|
if (chip & CHIP_TREX1)
|
|
voodoo->trexInit1[1] = val;
|
|
break;
|
|
|
|
case SST_nccTable0_Y0:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].y[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].y[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable0_Y1:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].y[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].y[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable0_Y2:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].y[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].y[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable0_Y3:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].y[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].y[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
|
|
case SST_nccTable0_I0:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].i[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].i[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_I2:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].i[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].i[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_Q0:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].q[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].q[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_Q2:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].i[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].i[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
if (val & (1 << 31))
|
|
{
|
|
int p = (val >> 23) & 0xfe;
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->palette[0][p].u = val | 0xff000000;
|
|
voodoo->palette_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->palette[1][p].u = val | 0xff000000;
|
|
voodoo->palette_dirty[1] = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SST_nccTable0_I1:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].i[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].i[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_I3:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].i[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].i[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_Q1:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].q[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].q[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
case SST_nccTable0_Q3:
|
|
if (!(val & (1 << 31)))
|
|
{
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][0].q[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][0].q[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
}
|
|
if (val & (1 << 31))
|
|
{
|
|
int p = ((val >> 23) & 0xfe) | 0x01;
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->palette[0][p].u = val | 0xff000000;
|
|
voodoo->palette_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->palette[1][p].u = val | 0xff000000;
|
|
voodoo->palette_dirty[1] = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SST_nccTable1_Y0:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].y[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].y[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Y1:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].y[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].y[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Y2:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].y[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].y[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Y3:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].y[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].y[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_I0:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].i[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].i[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_I1:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].i[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].i[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_I2:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].i[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].i[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_I3:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].i[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].i[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Q0:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].q[0] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].q[0] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Q1:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].q[1] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].q[1] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Q2:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].q[2] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].q[2] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
case SST_nccTable1_Q3:
|
|
if (chip & CHIP_TREX0)
|
|
{
|
|
voodoo->nccTable[0][1].q[3] = val;
|
|
voodoo->ncc_dirty[0] = 1;
|
|
}
|
|
if (chip & CHIP_TREX1)
|
|
{
|
|
voodoo->nccTable[1][1].q[3] = val;
|
|
voodoo->ncc_dirty[1] = 1;
|
|
}
|
|
break;
|
|
|
|
case SST_userIntrCMD:
|
|
fatal("userIntrCMD write %08x from FIFO\n", val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static 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;
|
|
|
|
x = (addr >> 1) & 0x3ff;
|
|
y = (addr >> 11) & 0x3ff;
|
|
read_addr = voodoo->fb_read_offset + (x << 1) + (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;
|
|
}
|
|
static 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;
|
|
|
|
x = addr & 0x7fe;
|
|
y = (addr >> 11) & 0x3ff;
|
|
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);
|
|
}
|
|
|
|
static 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;
|
|
|
|
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);
|
|
}
|
|
|
|
x = addr & 0x7fe;
|
|
y = (addr >> 11) & 0x3ff;
|
|
|
|
if (voodoo->fb_write_offset == voodoo->params.front_offset)
|
|
voodoo->dirty_line[y] = 1;
|
|
|
|
write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width);
|
|
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;
|
|
int32_t w_depth = 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;
|
|
}
|
|
}
|
|
|
|
|
|
static 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, 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);
|
|
}
|
|
|
|
x = addr & 0x7fe;
|
|
y = (addr >> 11) & 0x3ff;
|
|
|
|
if (voodoo->fb_write_offset == voodoo->params.front_offset)
|
|
voodoo->dirty_line[y] = 1;
|
|
|
|
write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width);
|
|
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;
|
|
int32_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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static 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;
|
|
|
|
// pclog("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat);
|
|
|
|
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))
|
|
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]);
|
|
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);
|
|
}
|
|
*(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val;
|
|
}
|
|
|
|
#define WAKE_DELAY (TIMER_USEC * 100)
|
|
static inline void wake_fifo_thread(voodoo_t *voodoo)
|
|
{
|
|
if (!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_process();
|
|
voodoo->wake_timer = WAKE_DELAY;
|
|
timer_update_outstanding();
|
|
}
|
|
}
|
|
|
|
static inline void wake_fifo_thread_now(voodoo_t *voodoo)
|
|
{
|
|
thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
|
|
}
|
|
|
|
static void voodoo_wake_timer(void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
|
|
voodoo->wake_timer = 0;
|
|
|
|
thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/
|
|
}
|
|
|
|
static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val)
|
|
{
|
|
fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK];
|
|
int c;
|
|
|
|
if (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*/
|
|
}
|
|
}
|
|
|
|
fifo->val = val;
|
|
fifo->addr_type = addr_type;
|
|
|
|
voodoo->fifo_write_idx++;
|
|
|
|
if (FIFO_ENTRIES > 0xe000)
|
|
wake_fifo_thread(voodoo);
|
|
}
|
|
|
|
static uint16_t voodoo_readw(uint32_t addr, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
|
|
addr &= 0xffffff;
|
|
|
|
cycles -= voodoo->read_time;
|
|
|
|
if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/
|
|
{
|
|
voodoo->flush = 1;
|
|
while (!FIFO_EMPTY)
|
|
{
|
|
wake_fifo_thread_now(voodoo);
|
|
thread_wait_event(voodoo->fifo_not_full_event, 1);
|
|
}
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo->flush = 0;
|
|
|
|
return voodoo_fb_readw(addr, voodoo);
|
|
}
|
|
|
|
return 0xffff;
|
|
}
|
|
|
|
static void voodoo_flush(voodoo_t *voodoo)
|
|
{
|
|
voodoo->flush = 1;
|
|
while (!FIFO_EMPTY)
|
|
{
|
|
wake_fifo_thread_now(voodoo);
|
|
thread_wait_event(voodoo->fifo_not_full_event, 1);
|
|
}
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo->flush = 0;
|
|
}
|
|
|
|
static uint32_t voodoo_readl(uint32_t addr, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
uint32_t temp;
|
|
int fifo_size;
|
|
voodoo->rd_count++;
|
|
addr &= 0xffffff;
|
|
|
|
cycles -= voodoo->read_time;
|
|
|
|
if (addr & 0x800000) /*Texture*/
|
|
{
|
|
}
|
|
else if (addr & 0x400000) /*Framebuffer*/
|
|
{
|
|
voodoo->flush = 1;
|
|
while (!FIFO_EMPTY)
|
|
{
|
|
wake_fifo_thread_now(voodoo);
|
|
thread_wait_event(voodoo->fifo_not_full_event, 1);
|
|
}
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo->flush = 0;
|
|
|
|
temp = voodoo_fb_readl(addr, voodoo);
|
|
}
|
|
else switch (addr & 0x3fc)
|
|
{
|
|
case SST_status:
|
|
fifo_size = 0xffff - FIFO_ENTRIES;
|
|
temp = fifo_size << 12;
|
|
if (fifo_size < 0x40)
|
|
temp |= fifo_size;
|
|
else
|
|
temp |= 0x3f;
|
|
temp |= (voodoo->swap_count << 28);
|
|
if (voodoo->cmd_written - voodoo->cmd_read)
|
|
temp |= 0x380; /*Busy*/
|
|
if (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr)
|
|
temp |= 0x380; /*Busy*/
|
|
if (!voodoo->v_retrace)
|
|
temp |= 0x40;
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
|
|
case SST_fbzColorPath:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.fbzColorPath;
|
|
break;
|
|
case SST_fogMode:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.fogMode;
|
|
break;
|
|
case SST_alphaMode:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.alphaMode;
|
|
break;
|
|
case SST_fbzMode:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.fbzMode;
|
|
break;
|
|
case SST_lfbMode:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->lfbMode;
|
|
break;
|
|
case SST_clipLeftRight:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.clipRight | (voodoo->params.clipLeft << 16);
|
|
break;
|
|
case SST_clipLowYHighY:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16);
|
|
break;
|
|
|
|
case SST_stipple:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.stipple;
|
|
break;
|
|
case SST_color0:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.color0;
|
|
break;
|
|
case SST_color1:
|
|
voodoo_flush(voodoo);
|
|
temp = voodoo->params.color1;
|
|
break;
|
|
|
|
case SST_fbiPixelsIn:
|
|
temp = voodoo->fbiPixelsIn & 0xffffff;
|
|
break;
|
|
case SST_fbiChromaFail:
|
|
temp = voodoo->fbiChromaFail & 0xffffff;
|
|
break;
|
|
case SST_fbiZFuncFail:
|
|
temp = voodoo->fbiZFuncFail & 0xffffff;
|
|
break;
|
|
case SST_fbiAFuncFail:
|
|
temp = voodoo->fbiAFuncFail & 0xffffff;
|
|
break;
|
|
case SST_fbiPixelsOut:
|
|
temp = voodoo->fbiPixelsOut & 0xffffff;
|
|
break;
|
|
|
|
case SST_fbiInit4:
|
|
temp = voodoo->fbiInit4;
|
|
break;
|
|
case SST_fbiInit0:
|
|
temp = voodoo->fbiInit0;
|
|
break;
|
|
case SST_fbiInit1:
|
|
temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/
|
|
break;
|
|
case SST_fbiInit2:
|
|
if (voodoo->initEnable & 0x04)
|
|
temp = voodoo->dac_readdata;
|
|
else
|
|
temp = voodoo->fbiInit2;
|
|
break;
|
|
case SST_fbiInit3:
|
|
temp = voodoo->fbiInit3;
|
|
break;
|
|
|
|
case SST_hvRetrace:
|
|
timer_clock();
|
|
temp = voodoo->line & 0x1fff;
|
|
temp |= ((((voodoo->line_time - voodoo->timer_count) * voodoo->h_total) / voodoo->timer_count) << 16) & 0x7ff0000;
|
|
break;
|
|
|
|
case SST_fbiInit5:
|
|
temp = voodoo->fbiInit5 & ~0x41ff;
|
|
break;
|
|
case SST_fbiInit6:
|
|
temp = voodoo->fbiInit6;
|
|
break;
|
|
case SST_fbiInit7:
|
|
temp = voodoo->fbiInit7 & ~0xff;
|
|
break;
|
|
|
|
case SST_cmdFifoBaseAddr:
|
|
temp = voodoo->cmdfifo_base >> 12;
|
|
temp |= (voodoo->cmdfifo_end >> 12) << 16;
|
|
break;
|
|
|
|
case SST_cmdFifoRdPtr:
|
|
temp = voodoo->cmdfifo_rp;
|
|
break;
|
|
case SST_cmdFifoAMin:
|
|
temp = voodoo->cmdfifo_amin;
|
|
break;
|
|
case SST_cmdFifoAMax:
|
|
temp = voodoo->cmdfifo_amax;
|
|
break;
|
|
case SST_cmdFifoDepth:
|
|
temp = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd;
|
|
break;
|
|
|
|
default:
|
|
fatal("voodoo_readl : bad addr %08X\n", addr);
|
|
temp = 0xffffffff;
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
static void voodoo_writew(uint32_t addr, uint16_t val, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
voodoo->wr_count++;
|
|
addr &= 0xffffff;
|
|
|
|
if (addr == voodoo->last_write_addr+4)
|
|
cycles -= voodoo->burst_time;
|
|
else
|
|
cycles -= voodoo->write_time;
|
|
voodoo->last_write_addr = addr;
|
|
|
|
if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/
|
|
queue_command(voodoo, addr | FIFO_WRITEW_FB, val);
|
|
}
|
|
|
|
static 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 = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT));
|
|
}
|
|
|
|
static void voodoo_writel(uint32_t addr, uint32_t val, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
union
|
|
{
|
|
uint32_t i;
|
|
float f;
|
|
} tempif;
|
|
|
|
tempif.i = val;
|
|
voodoo->wr_count++;
|
|
|
|
addr &= 0xffffff;
|
|
|
|
if (addr == voodoo->last_write_addr+4)
|
|
cycles -= voodoo->burst_time;
|
|
else
|
|
cycles -= voodoo->write_time;
|
|
voodoo->last_write_addr = addr;
|
|
|
|
if (addr & 0x800000) /*Texture*/
|
|
{
|
|
voodoo->tex_count++;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_TEX, val);
|
|
}
|
|
else if (addr & 0x400000) /*Framebuffer*/
|
|
{
|
|
queue_command(voodoo, addr | FIFO_WRITEL_FB, val);
|
|
}
|
|
else if ((addr & 0x200000) && (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE))
|
|
{
|
|
// pclog("Write CMDFIFO %08x(%08x) %08x %08x\n", addr, voodoo->cmdfifo_base + (addr & 0x3fffc), val, (voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask);
|
|
*(uint32_t *)&voodoo->fb_mem[(voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask] = val;
|
|
voodoo->cmdfifo_depth_wr++;
|
|
if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20)
|
|
wake_fifo_thread(voodoo);
|
|
}
|
|
else switch (addr & 0x3fc)
|
|
{
|
|
case SST_intrCtrl:
|
|
fatal("intrCtrl write %08x\n", val);
|
|
break;
|
|
|
|
case SST_userIntrCMD:
|
|
fatal("userIntrCMD write %08x\n", val);
|
|
break;
|
|
|
|
case SST_swapbufferCMD:
|
|
voodoo->cmd_written++;
|
|
voodoo->swap_count++;
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
return;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
case SST_triangleCMD:
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
return;
|
|
voodoo->cmd_written++;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
case SST_ftriangleCMD:
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
return;
|
|
voodoo->cmd_written++;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
case SST_fastfillCMD:
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
return;
|
|
voodoo->cmd_written++;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
case SST_nopCMD:
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
return;
|
|
voodoo->cmd_written++;
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
if (!voodoo->voodoo_busy)
|
|
wake_fifo_thread(voodoo);
|
|
break;
|
|
|
|
case SST_fbiInit4:
|
|
if (voodoo->initEnable & 0x01)
|
|
{
|
|
voodoo->fbiInit4 = val;
|
|
voodoo->read_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit4 & 1) ? 2 : 1);
|
|
// pclog("fbiInit4 write %08x - read_time=%i\n", val, voodoo->read_time);
|
|
}
|
|
break;
|
|
case SST_backPorch:
|
|
voodoo->backPorch = val;
|
|
break;
|
|
case SST_videoDimensions:
|
|
voodoo->videoDimensions = val;
|
|
voodoo->h_disp = (val & 0xfff) + 1;
|
|
voodoo->v_disp = (val >> 16) & 0xfff;
|
|
break;
|
|
case SST_fbiInit0:
|
|
if (voodoo->initEnable & 0x01)
|
|
{
|
|
voodoo->fbiInit0 = val;
|
|
svga_set_override(voodoo->svga, val & 1);
|
|
if (val & FBIINIT0_GRAPHICS_RESET)
|
|
{
|
|
/*Reset display/draw buffer selection. This may not actually
|
|
happen here on a real Voodoo*/
|
|
voodoo->disp_buffer = 0;
|
|
voodoo->draw_buffer = 1;
|
|
voodoo_recalc(voodoo);
|
|
voodoo->front_offset = voodoo->params.front_offset;
|
|
}
|
|
}
|
|
break;
|
|
case SST_fbiInit1:
|
|
if (voodoo->initEnable & 0x01)
|
|
{
|
|
voodoo->fbiInit1 = val;
|
|
voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0);
|
|
voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1);
|
|
// pclog("fbiInit1 write %08x - write_time=%i burst_time=%i\n", val, voodoo->write_time, voodoo->burst_time);
|
|
}
|
|
break;
|
|
case SST_fbiInit2:
|
|
if (voodoo->initEnable & 0x01)
|
|
{
|
|
voodoo->fbiInit2 = val;
|
|
voodoo_recalc(voodoo);
|
|
}
|
|
break;
|
|
case SST_fbiInit3:
|
|
if (voodoo->initEnable & 0x01)
|
|
voodoo->fbiInit3 = val;
|
|
break;
|
|
|
|
case SST_hSync:
|
|
voodoo->hSync = val;
|
|
voodoo->h_total = (val & 0xffff) + (val >> 16);
|
|
voodoo_pixelclock_update(voodoo);
|
|
break;
|
|
case SST_vSync:
|
|
voodoo->vSync = val;
|
|
voodoo->v_total = (val & 0xffff) + (val >> 16);
|
|
break;
|
|
|
|
case SST_clutData:
|
|
voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff;
|
|
voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff;
|
|
voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff;
|
|
if (val & 0x20000000)
|
|
{
|
|
voodoo->clutData[(val >> 24) & 0x3f].b = 255;
|
|
voodoo->clutData[(val >> 24) & 0x3f].g = 255;
|
|
voodoo->clutData[(val >> 24) & 0x3f].r = 255;
|
|
}
|
|
voodoo->clutData_dirty = 1;
|
|
break;
|
|
|
|
case SST_dacData:
|
|
voodoo->dac_reg = (val >> 8) & 7;
|
|
voodoo->dac_readdata = 0xff;
|
|
if (val & 0x800)
|
|
{
|
|
// pclog(" dacData read %i %02X\n", voodoo->dac_reg, voodoo->dac_data[7]);
|
|
if (voodoo->dac_reg == 5)
|
|
{
|
|
switch (voodoo->dac_data[7])
|
|
{
|
|
case 0x01: voodoo->dac_readdata = 0x55; break;
|
|
case 0x07: voodoo->dac_readdata = 0x71; break;
|
|
case 0x0b: voodoo->dac_readdata = 0x79; break;
|
|
}
|
|
}
|
|
else
|
|
voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_readdata];
|
|
}
|
|
else
|
|
{
|
|
if (voodoo->dac_reg == 5)
|
|
{
|
|
if (!voodoo->dac_reg_ff)
|
|
voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff00) | val;
|
|
else
|
|
voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff) | (val << 8);
|
|
// pclog("Write PLL reg %x %04x\n", voodoo->dac_data[4] & 0xf, voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf]);
|
|
voodoo->dac_reg_ff = !voodoo->dac_reg_ff;
|
|
if (!voodoo->dac_reg_ff)
|
|
voodoo->dac_data[4]++;
|
|
|
|
}
|
|
else
|
|
{
|
|
voodoo->dac_data[voodoo->dac_reg] = val & 0xff;
|
|
voodoo->dac_reg_ff = 0;
|
|
}
|
|
voodoo_pixelclock_update(voodoo);
|
|
}
|
|
break;
|
|
|
|
case SST_scrFilter:
|
|
if (voodoo->initEnable & 0x01)
|
|
{
|
|
voodoo->scrfilterEnabled = 1;
|
|
voodoo->scrfilterThreshold = val; /* update the threshold values and generate a new lookup table if necessary */
|
|
|
|
if (val < 1)
|
|
voodoo->scrfilterEnabled = 0;
|
|
voodoo_threshold_check(voodoo);
|
|
pclog("Voodoo Filter: %06x\n", val);
|
|
}
|
|
break;
|
|
|
|
case SST_fbiInit5:
|
|
if (voodoo->initEnable & 0x01)
|
|
voodoo->fbiInit5 = val;
|
|
break;
|
|
case SST_fbiInit6:
|
|
if (voodoo->initEnable & 0x01)
|
|
voodoo->fbiInit6 = val;
|
|
break;
|
|
case SST_fbiInit7:
|
|
if (voodoo->initEnable & 0x01)
|
|
voodoo->fbiInit7 = val;
|
|
break;
|
|
|
|
case SST_cmdFifoBaseAddr:
|
|
voodoo->cmdfifo_base = (val & 0x3ff) << 12;
|
|
voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12;
|
|
// pclog("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
|
|
break;
|
|
|
|
case SST_cmdFifoRdPtr:
|
|
voodoo->cmdfifo_rp = val;
|
|
break;
|
|
case SST_cmdFifoAMin:
|
|
voodoo->cmdfifo_amin = val;
|
|
break;
|
|
case SST_cmdFifoAMax:
|
|
voodoo->cmdfifo_amax = val;
|
|
break;
|
|
case SST_cmdFifoDepth:
|
|
voodoo->cmdfifo_depth_rd = 0;
|
|
voodoo->cmdfifo_depth_wr = val & 0xffff;
|
|
break;
|
|
|
|
default:
|
|
if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)
|
|
{
|
|
fatal("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val);
|
|
}
|
|
else
|
|
{
|
|
queue_command(voodoo, addr | FIFO_WRITEL_REG, val);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint32_t cmdfifo_get(voodoo_t *voodoo)
|
|
{
|
|
uint32_t val;
|
|
|
|
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];
|
|
|
|
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)
|
|
};
|
|
|
|
static void 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:
|
|
voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
|
|
break;
|
|
case FIFO_WRITEW_FB:
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
|
|
break;
|
|
case FIFO_WRITEL_FB:
|
|
wait_for_render_thread_idle(voodoo);
|
|
voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
|
|
break;
|
|
case FIFO_WRITEL_TEX:
|
|
if (!(fifo->addr_type & 0x400000))
|
|
voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo);
|
|
break;
|
|
}
|
|
voodoo->fifo_read_idx++;
|
|
fifo->addr_type = FIFO_INVALID;
|
|
|
|
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_depth_rd != voodoo->cmdfifo_depth_wr)
|
|
{
|
|
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 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 & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD ||
|
|
(addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
|
|
voodoo->cmd_written++;
|
|
|
|
voodoo_reg_writel(addr, val, voodoo);
|
|
|
|
if (header & (1 << 15))
|
|
addr += 4;
|
|
}
|
|
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 & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD ||
|
|
(addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
|
|
voodoo->cmd_written++;
|
|
|
|
voodoo_reg_writel(addr, val, voodoo);
|
|
}
|
|
|
|
addr += 4;
|
|
mask >>= 1;
|
|
}
|
|
while (num--)
|
|
cmdfifo_get(voodoo);
|
|
break;
|
|
|
|
case 5:
|
|
if (header & 0x3fc0000)
|
|
fatal("CMDFIFO packet 5 has byte disables set %08x\n", header);
|
|
num = (header >> 3) & 0x7ffff;
|
|
addr = cmdfifo_get(voodoo) & 0xffffff;
|
|
// pclog("CMDFIFO5 addr=%08x num=%i\n", addr, num);
|
|
switch (header >> 30)
|
|
{
|
|
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:
|
|
pclog("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp);
|
|
}
|
|
|
|
end_time = timer_read();
|
|
voodoo_time += end_time - start_time;
|
|
}
|
|
|
|
voodoo->voodoo_busy = 0;
|
|
}
|
|
}
|
|
|
|
static void voodoo_recalcmapping(voodoo_t *voodoo)
|
|
{
|
|
if (voodoo->pci_enable && voodoo->memBaseAddr)
|
|
{
|
|
pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr);
|
|
mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000);
|
|
}
|
|
else
|
|
{
|
|
pclog("voodoo_recalcmapping : disabled\n");
|
|
mem_mapping_disable(&voodoo->mapping);
|
|
}
|
|
}
|
|
|
|
uint8_t voodoo_pci_read(int func, int addr, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
|
|
if (func)
|
|
return 0;
|
|
|
|
// pclog("Voodoo PCI read %08X PC=%08x\n", addr, cpu_state.pc);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x00: return 0x1a; /*3dfx*/
|
|
case 0x01: return 0x12;
|
|
|
|
case 0x02:
|
|
if (voodoo->type == VOODOO_2)
|
|
return 0x02; /*Voodoo 2*/
|
|
else
|
|
return 0x01; /*SST-1 (Voodoo Graphics)*/
|
|
case 0x03: return 0x00;
|
|
|
|
case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/
|
|
|
|
case 0x08: return 2; /*Revision ID*/
|
|
case 0x09: return 0; /*Programming interface*/
|
|
case 0x0a: return 0;
|
|
case 0x0b: return 0x04;
|
|
|
|
case 0x10: return 0x00; /*memBaseAddr*/
|
|
case 0x11: return 0x00;
|
|
case 0x12: return 0x00;
|
|
case 0x13: return voodoo->memBaseAddr >> 24;
|
|
|
|
case 0x40:
|
|
return voodoo->initEnable & 0xff;
|
|
case 0x41:
|
|
if (voodoo->type == VOODOO_2)
|
|
return 0x50 | ((voodoo->initEnable >> 8) & 0x0f);
|
|
return (voodoo->initEnable >> 8) & 0x0f;
|
|
case 0x42:
|
|
return (voodoo->initEnable >> 16) & 0xff;
|
|
case 0x43:
|
|
return (voodoo->initEnable >> 24) & 0xff;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void voodoo_pci_write(int func, int addr, uint8_t val, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
|
|
if (func)
|
|
return;
|
|
|
|
// pclog("Voodoo PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc);
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x04:
|
|
voodoo->pci_enable = val & 2;
|
|
voodoo_recalcmapping(voodoo);
|
|
break;
|
|
|
|
case 0x13:
|
|
voodoo->memBaseAddr = val << 24;
|
|
voodoo_recalcmapping(voodoo);
|
|
break;
|
|
|
|
case 0x40:
|
|
voodoo->initEnable = (voodoo->initEnable & ~0x000000ff) | val;
|
|
break;
|
|
case 0x41:
|
|
voodoo->initEnable = (voodoo->initEnable & ~0x0000ff00) | (val << 8);
|
|
break;
|
|
case 0x42:
|
|
voodoo->initEnable = (voodoo->initEnable & ~0x00ff0000) | (val << 16);
|
|
break;
|
|
case 0x43:
|
|
voodoo->initEnable = (voodoo->initEnable & ~0xff000000) | (val << 24);
|
|
break;
|
|
}
|
|
}
|
|
|
|
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 */
|
|
|
|
static 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;
|
|
}
|
|
}
|
|
|
|
static void voodoo_generate_filter_v2(voodoo_t *voodoo)
|
|
{
|
|
int g, h;
|
|
float difference;
|
|
float thiscol, thiscolg, thiscolb, lined;
|
|
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);
|
|
}
|
|
|
|
lined = g + 3;
|
|
if (lined > 255)
|
|
lined = 255;
|
|
voodoo->purpleline[g][0] = lined;
|
|
voodoo->purpleline[g][1] = 0;
|
|
voodoo->purpleline[g][2] = lined;
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0;
|
|
int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0;
|
|
|
|
if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
|
|
{
|
|
if (voodoo->line < voodoo->v_disp)
|
|
{
|
|
if (voodoo->dirty_line[voodoo->line])
|
|
{
|
|
uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add];
|
|
uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width];
|
|
int x;
|
|
|
|
voodoo->dirty_line[voodoo->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)
|
|
{
|
|
int j, offset;
|
|
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] = voodoo->video_16to32[src[x]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval))
|
|
{
|
|
memset(voodoo->dirty_line, 1, 1024);
|
|
voodoo->retrace_count = 0;
|
|
voodoo->front_offset = voodoo->swap_offset;
|
|
voodoo->swap_count--;
|
|
voodoo->swap_pending = 0;
|
|
thread_set_event(voodoo->wake_fifo_thread);
|
|
voodoo->frame_count++;
|
|
}
|
|
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)
|
|
voodoo->timer_count += voodoo->line_time;
|
|
else
|
|
voodoo->timer_count += TIMER_USEC * 32;
|
|
}
|
|
|
|
static void voodoo_add_status_info(char *s, int max_len, void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
char temps[256];
|
|
int pixel_count_current[2];
|
|
int pixel_count_total;
|
|
int texel_count_current[2];
|
|
int texel_count_total;
|
|
uint64_t new_time = timer_read();
|
|
uint64_t status_diff = new_time - status_time;
|
|
status_time = new_time;
|
|
|
|
if (!status_diff)
|
|
status_diff = 1;
|
|
|
|
svga_add_status_info(s, max_len, &voodoo->svga);
|
|
|
|
pixel_count_current[0] = voodoo->pixel_count[0];
|
|
pixel_count_current[1] = voodoo->pixel_count[1];
|
|
pixel_count_total = (pixel_count_current[0] + pixel_count_current[1]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1]);
|
|
texel_count_current[0] = voodoo->texel_count[0];
|
|
texel_count_current[1] = voodoo->texel_count[1];
|
|
texel_count_total = (texel_count_current[0] + texel_count_current[1]) - (voodoo->texel_count_old[0] + voodoo->texel_count_old[1]);
|
|
sprintf(temps, "%f Mpixels/sec (%f)\n%f Mtexels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\n%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n"/*%d reads/sec\n%d write/sec\n%d tex/sec\n*/,
|
|
(double)pixel_count_total/1000000.0,
|
|
((double)pixel_count_total/1000000.0) / ((double)voodoo_render_time[0] / status_diff),
|
|
(double)texel_count_total/1000000.0,
|
|
((double)texel_count_total/1000000.0) / ((double)voodoo_render_time[0] / status_diff),
|
|
(double)voodoo->tri_count/1000.0, ((double)voodoo_time * 100.0) / timer_freq, ((double)voodoo_time * 100.0) / status_diff, voodoo->frame_count, voodoo_recomp,
|
|
((double)voodoo_render_time[0] * 100.0) / timer_freq, ((double)voodoo_render_time[0] * 100.0) / status_diff,
|
|
((double)voodoo_render_time[1] * 100.0) / timer_freq, ((double)voodoo_render_time[1] * 100.0) / status_diff);
|
|
strncat(s, temps, max_len);
|
|
|
|
voodoo->pixel_count_old[0] = pixel_count_current[0];
|
|
voodoo->pixel_count_old[1] = pixel_count_current[1];
|
|
voodoo->texel_count_old[0] = texel_count_current[0];
|
|
voodoo->texel_count_old[1] = texel_count_current[1];
|
|
voodoo->tri_count = voodoo->frame_count = 0;
|
|
voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0;
|
|
voodoo_time = 0;
|
|
voodoo_render_time[0] = voodoo_render_time[1] = 0;
|
|
voodoo_recomp = 0;
|
|
}
|
|
|
|
static void voodoo_speed_changed(void *p)
|
|
{
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
|
|
voodoo_pixelclock_update(voodoo);
|
|
voodoo->read_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit4 & 1) ? 2 : 1);
|
|
voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0);
|
|
voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1);
|
|
// pclog("Voodoo read_time=%i write_time=%i burst_time=%i %08x %08x\n", voodoo->read_time, voodoo->write_time, voodoo->burst_time, voodoo->fbiInit1, voodoo->fbiInit4);
|
|
}
|
|
|
|
void *voodoo_init()
|
|
{
|
|
int c;
|
|
voodoo_t *voodoo = malloc(sizeof(voodoo_t));
|
|
memset(voodoo, 0, sizeof(voodoo_t));
|
|
|
|
voodoo->bilinear_enabled = device_get_config_int("bilinear");
|
|
voodoo->scrfilter = device_get_config_int("dacfilter");
|
|
voodoo->texture_size = device_get_config_int("texture_memory");
|
|
voodoo->texture_mask = (voodoo->texture_size << 20) - 1;
|
|
voodoo->fb_size = device_get_config_int("framebuffer_memory");
|
|
voodoo->fb_mask = (voodoo->fb_size << 20) - 1;
|
|
voodoo->render_threads = device_get_config_int("render_threads");
|
|
voodoo->odd_even_mask = voodoo->render_threads - 1;
|
|
#ifndef NO_CODEGEN
|
|
voodoo->use_recompiler = device_get_config_int("recompiler");
|
|
#endif
|
|
voodoo->type = device_get_config_int("type");
|
|
switch (voodoo->type)
|
|
{
|
|
case VOODOO_1:
|
|
voodoo->dual_tmus = 0;
|
|
break;
|
|
case VOODOO_SB50:
|
|
voodoo->dual_tmus = 1;
|
|
break;
|
|
case VOODOO_2:
|
|
voodoo->dual_tmus = 1;
|
|
break;
|
|
}
|
|
|
|
if (voodoo->type == VOODOO_2) /*generate filter lookup tables*/
|
|
voodoo_generate_filter_v2(voodoo);
|
|
else
|
|
voodoo_generate_filter_v1(voodoo);
|
|
|
|
pci_add(voodoo_pci_read, voodoo_pci_write, voodoo);
|
|
|
|
mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo);
|
|
|
|
voodoo->fb_mem = malloc(4 * 1024 * 1024);
|
|
voodoo->tex_mem[0] = malloc(voodoo->texture_size * 1024 * 1024);
|
|
if (voodoo->dual_tmus)
|
|
voodoo->tex_mem[1] = malloc(voodoo->texture_size * 1024 * 1024);
|
|
voodoo->tex_mem_w[0] = (uint16_t *)voodoo->tex_mem[0];
|
|
voodoo->tex_mem_w[1] = (uint16_t *)voodoo->tex_mem[1];
|
|
|
|
for (c = 0; c < TEX_CACHE_MAX; c++)
|
|
{
|
|
voodoo->texture_cache[0][c].data = malloc((256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1) * 4);
|
|
voodoo->texture_cache[0][c].base = -1; /*invalid*/
|
|
voodoo->texture_cache[0][c].refcount = 0;
|
|
if (voodoo->dual_tmus)
|
|
{
|
|
voodoo->texture_cache[1][c].data = malloc((256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1) * 4);
|
|
voodoo->texture_cache[1][c].base = -1; /*invalid*/
|
|
voodoo->texture_cache[1][c].refcount = 0;
|
|
}
|
|
}
|
|
|
|
timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo);
|
|
|
|
voodoo->svga = svga_get_pri();
|
|
voodoo->fbiInit0 = 0;
|
|
|
|
voodoo->wake_fifo_thread = thread_create_event();
|
|
voodoo->wake_render_thread[0] = thread_create_event();
|
|
voodoo->wake_render_thread[1] = thread_create_event();
|
|
voodoo->wake_main_thread = thread_create_event();
|
|
voodoo->fifo_not_full_event = thread_create_event();
|
|
voodoo->render_not_full_event[0] = thread_create_event();
|
|
voodoo->render_not_full_event[1] = thread_create_event();
|
|
voodoo->fifo_thread = thread_create(fifo_thread, voodoo);
|
|
voodoo->render_thread[0] = thread_create(render_thread_1, voodoo);
|
|
if (voodoo->render_threads == 2)
|
|
voodoo->render_thread[1] = thread_create(render_thread_2, voodoo);
|
|
|
|
timer_add(voodoo_wake_timer, &voodoo->wake_timer, &voodoo->wake_timer, (void *)voodoo);
|
|
|
|
for (c = 0; c < 0x100; c++)
|
|
{
|
|
rgb332[c].r = c & 0xe0;
|
|
rgb332[c].g = (c << 3) & 0xe0;
|
|
rgb332[c].b = (c << 6) & 0xc0;
|
|
rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6);
|
|
rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6);
|
|
rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2);
|
|
rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4);
|
|
rgb332[c].a = 0xff;
|
|
|
|
ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4);
|
|
ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4);
|
|
ai44[c].g = ai44[c].b = ai44[c].r;
|
|
}
|
|
|
|
for (c = 0; c < 0x10000; c++)
|
|
{
|
|
rgb565[c].r = (c >> 8) & 0xf8;
|
|
rgb565[c].g = (c >> 3) & 0xfc;
|
|
rgb565[c].b = (c << 3) & 0xf8;
|
|
rgb565[c].r |= (rgb565[c].r >> 5);
|
|
rgb565[c].g |= (rgb565[c].g >> 6);
|
|
rgb565[c].b |= (rgb565[c].b >> 5);
|
|
rgb565[c].a = 0xff;
|
|
|
|
argb1555[c].r = (c >> 7) & 0xf8;
|
|
argb1555[c].g = (c >> 2) & 0xf8;
|
|
argb1555[c].b = (c << 3) & 0xf8;
|
|
argb1555[c].r |= (argb1555[c].r >> 5);
|
|
argb1555[c].g |= (argb1555[c].g >> 5);
|
|
argb1555[c].b |= (argb1555[c].b >> 5);
|
|
argb1555[c].a = (c & 0x8000) ? 0xff : 0;
|
|
|
|
argb4444[c].a = (c >> 8) & 0xf0;
|
|
argb4444[c].r = (c >> 4) & 0xf0;
|
|
argb4444[c].g = c & 0xf0;
|
|
argb4444[c].b = (c << 4) & 0xf0;
|
|
argb4444[c].a |= (argb4444[c].a >> 4);
|
|
argb4444[c].r |= (argb4444[c].r >> 4);
|
|
argb4444[c].g |= (argb4444[c].g >> 4);
|
|
argb4444[c].b |= (argb4444[c].b >> 4);
|
|
|
|
ai88[c].a = (c >> 8);
|
|
ai88[c].r = c & 0xff;
|
|
ai88[c].g = c & 0xff;
|
|
ai88[c].b = c & 0xff;
|
|
}
|
|
#ifndef NO_CODEGEN
|
|
voodoo_codegen_init(voodoo);
|
|
#endif
|
|
|
|
voodoo->disp_buffer = 0;
|
|
voodoo->draw_buffer = 1;
|
|
|
|
return voodoo;
|
|
}
|
|
|
|
void voodoo_close(void *p)
|
|
{
|
|
FILE *f;
|
|
voodoo_t *voodoo = (voodoo_t *)p;
|
|
int c;
|
|
|
|
#ifndef RELEASE_BUILD
|
|
f = romfopen("texram.dmp", "wb");
|
|
fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f);
|
|
fclose(f);
|
|
if (voodoo->dual_tmus)
|
|
{
|
|
f = romfopen("texram2.dmp", "wb");
|
|
fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f);
|
|
fclose(f);
|
|
}
|
|
#endif
|
|
|
|
thread_kill(voodoo->fifo_thread);
|
|
thread_kill(voodoo->render_thread[0]);
|
|
if (voodoo->render_threads == 2)
|
|
thread_kill(voodoo->render_thread[1]);
|
|
thread_destroy_event(voodoo->fifo_not_full_event);
|
|
thread_destroy_event(voodoo->wake_main_thread);
|
|
thread_destroy_event(voodoo->wake_fifo_thread);
|
|
thread_destroy_event(voodoo->wake_render_thread[0]);
|
|
thread_destroy_event(voodoo->wake_render_thread[1]);
|
|
thread_destroy_event(voodoo->render_not_full_event[0]);
|
|
thread_destroy_event(voodoo->render_not_full_event[1]);
|
|
|
|
for (c = 0; c < TEX_CACHE_MAX; c++)
|
|
{
|
|
if (voodoo->dual_tmus)
|
|
free(voodoo->texture_cache[1][c].data);
|
|
free(voodoo->texture_cache[0][c].data);
|
|
}
|
|
#ifndef NO_CODEGEN
|
|
voodoo_codegen_close(voodoo);
|
|
#endif
|
|
free(voodoo->fb_mem);
|
|
if (voodoo->dual_tmus)
|
|
free(voodoo->tex_mem[1]);
|
|
free(voodoo->tex_mem[0]);
|
|
free(voodoo);
|
|
}
|
|
|
|
static device_config_t voodoo_config[] =
|
|
{
|
|
{
|
|
.name = "type",
|
|
.description = "Voodoo type",
|
|
.type = CONFIG_SELECTION,
|
|
.selection =
|
|
{
|
|
{
|
|
.description = "Voodoo Graphics",
|
|
.value = VOODOO_1
|
|
},
|
|
{
|
|
.description = "Obsidian SB50 + Amethyst (2 TMUs)",
|
|
.value = VOODOO_SB50
|
|
},
|
|
{
|
|
.description = "Voodoo 2",
|
|
.value = VOODOO_2
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 0
|
|
},
|
|
{
|
|
.name = "framebuffer_memory",
|
|
.description = "Framebuffer memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection =
|
|
{
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = "4 MB",
|
|
.value = 4
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2
|
|
},
|
|
{
|
|
.name = "texture_memory",
|
|
.description = "Texture memory size",
|
|
.type = CONFIG_SELECTION,
|
|
.selection =
|
|
{
|
|
{
|
|
.description = "2 MB",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = "4 MB",
|
|
.value = 4
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2
|
|
},
|
|
{
|
|
.name = "bilinear",
|
|
.description = "Bilinear filtering",
|
|
.type = CONFIG_BINARY,
|
|
.default_int = 1
|
|
},
|
|
{
|
|
.name = "dacfilter",
|
|
.description = "Screen Filter",
|
|
.type = CONFIG_BINARY,
|
|
.default_int = 0
|
|
},
|
|
{
|
|
.name = "render_threads",
|
|
.description = "Render threads",
|
|
.type = CONFIG_SELECTION,
|
|
.selection =
|
|
{
|
|
{
|
|
.description = "1",
|
|
.value = 1
|
|
},
|
|
{
|
|
.description = "2",
|
|
.value = 2
|
|
},
|
|
{
|
|
.description = ""
|
|
}
|
|
},
|
|
.default_int = 2
|
|
},
|
|
#ifndef NO_CODEGEN
|
|
{
|
|
.name = "recompiler",
|
|
.description = "Recompiler",
|
|
.type = CONFIG_BINARY,
|
|
.default_int = 1
|
|
},
|
|
#endif
|
|
{
|
|
.type = -1
|
|
}
|
|
};
|
|
|
|
device_t voodoo_device =
|
|
{
|
|
"3DFX Voodoo Graphics",
|
|
0,
|
|
voodoo_init,
|
|
voodoo_close,
|
|
NULL,
|
|
voodoo_speed_changed,
|
|
NULL,
|
|
voodoo_add_status_info,
|
|
voodoo_config
|
|
};
|