3DFX emulation

Discussion of development and patch submission.
Post Reply
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

3DFX emulation

Post by SarahWalker »

As of rev 208 PCem now contains usable 3DFX emulation. For the moment this is just a basic 4 MB Voodoo 1 card. Most stuff seems to work so far...

Current issues :
  • No mipmapping.
  • Some precision issues (slightly wobbly triangles). Subpixel correction is probably wrong.
  • Some textures are off by 1 texel (particularly visible in GTA and Need For Speed 3).
  • Dithering is only enabled on gouraud shaded triangles, and even then the pattern is wrong. It's only good enough to get the Glide detection routines working.
  • Screamer Rally is a tad broken.
  • No speed limiting.
  • Refresh rates are wrong for every mode except 640x480@60Hz
  • Some other features still missing
  • Slow! Quake and friends are particularly bad, some other games will be more playable (eg Croc, GTA, FF7 etc).
  • It's theoretically possible that it might hang, though I think I've eliminated all the hanging bugs.
Some new screenshots:
pcem_nfs3_3dfx.png
pcem_nfs3_3dfx.png (160.19 KiB) Viewed 56613 times
pcem_turok_3dfx.png
pcem_turok_3dfx.png (174.91 KiB) Viewed 56613 times
pcem_ff7_3dfx.png
pcem_ff7_3dfx.png (159.66 KiB) Viewed 56613 times
pcem_shock2_3dfx.png
pcem_shock2_3dfx.png (124.96 KiB) Viewed 56613 times
pcem_expendable_3dfx.png
pcem_expendable_3dfx.png (211.63 KiB) Viewed 56613 times
pcem_resi2_3dfx.png
pcem_resi2_3dfx.png (156.5 KiB) Viewed 56613 times
User avatar
Bloody
Posts: 4
Joined: Sun 01 Mar, 2015 7:43 am
Location: Germany

Re: 3DFX emulation

Post by Bloody »

Great work, looks really awesome! :)
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

Q3A hangs just seconds after initialization. (r_glDriver 3dfxogl, using vg-w9x-q3.exe driver set). Also the gamma extension (WGL_3DFX_gamma_control) doesn't appear to be working.


Virge works without hang though


Trying to figure out where and how to adapt the filter via software

EDIT: Attempted a rough quick C port of the filter. It's slow and doesn't add purple lines yet nor can it work with the lack of dithering well. It's a start :)

Took a while because I could only test Turok. Tomb Raider crashed, Shadow Warrior refused to recognize the voodoo, and surprisingly Croc crashed.

Code: Select all

 if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
        {
                if (voodoo->line < voodoo->v_disp)
                {
                        uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32];
                        uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width];
                        int x;


			// leilei - dac screen filter, this is a messy hack with bad comment conventions
			//	a ton of it could be refactored, optimized, and vectorized
			//	this is just a rough initial implementation  by trial and error
			if (voodoo->scrfilter){

				unsigned rb[voodoo->h_disp];
				unsigned gb[voodoo->h_disp];
				unsigned bb[voodoo->h_disp];
			
				

				int j;
	
                   

				for (j=0;j<4;j++) // we must do 4 passes of this 
				{

		                        for (x = 0; x < voodoo->h_disp; x++)
		                        {
	
	
							#define FILTCAP (0.075 * 255)
							#define FILTCAPG (FILTCAP / 2)
								int ren;
								int r1,g1,b1;	
								int r2,g2,b2;	
								int rd,gd,bd;	
					
								if (j==0){
									// initial buffer grab
								   rb[x] = src[x] & 31;
								   gb[x] = (src[x] >> 5) & 63;
								   bb[x] = (src[x] >> 11) & 31;
								   rb[x+1] = src[x+1] & 31;
								   gb[x+1] = (src[x+1] >> 5) & 63;
								   bb[x+1] = (src[x+1] >> 11) & 31;
								}

								r1 = rb[x]; 
								g1 = gb[x];
								b1 = bb[x];
								r2 = rb[x+1]; 
								g2 = gb[x+1];
								b2 = bb[x+1];

					
								rd = r2 - r1;
								gd = g2 - g1;
								bd = b2 - b1;
					
								if (rd > FILTCAP ) 	rd = FILTCAP;
								if (gd > FILTCAPG) 	gd = FILTCAPG;
								if (bd > FILTCAP ) 	bd = FILTCAP;
					
								if (rd < -FILTCAP ) 	rd = -FILTCAP;
								if (gd < -FILTCAPG) 	gd = -FILTCAPG;
								if (bd < -FILTCAP ) 	bd = -FILTCAP;
					
						
					
								r1 += (rd/4);
								g1 += (gd/4);
								b1 += (bd/4);
					
						
								if (r1 < 0) r1 = 0;
								if (g1 < 0) g1 = 0;
								if (b1 < 0) b1 = 0;
						
								if (r1 > 255) r1 = 255;
								if (g1 > 255) g1 = 255;
								if (b1 > 255) b1 = 255;
					
								if (r2 < 0) r2 = 0;
								if (g2 < 0) g2 = 0;
								if (b2 < 0) b2 = 0;
						
								if (r2 > 255) r2 = 255;
								if (g2 > 255) g2 = 255;
								if (b2 > 255) b2 = 255;
	
						if (j==3)	 // final buffer write
							p[x] = (r1 << 3  | g1 << 10 | b1 << 19);
		
						else			// feedback filter linear passes
						{ 				
						rb[x] = r1;
						gb[x] = g1;
						bb[x] = b1;
						}


		                        }

				}

       			}
			else
			{
	                        for (x = 0; x < voodoo->h_disp; x++)
	                        {
	                                p[x] = video_16to32[src[x]];
	                        }

			}
                }
it's not accurate because it's missing the faint purple lines, and it seems to do it bidirectional (when it should be 3 to the right, 1 to the left IIRC)
Attachments
acclaimfilter.png
acclaimfilter.png (120.76 KiB) Viewed 56354 times
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Quake III hang should be fixed as of rev 213.
pcem_q3_3dfx_2.png
pcem_q3_3dfx_2.png (176.96 KiB) Viewed 56223 times
When you say Tomb Raider and Croc crashed, was that the emulator crashing or the games? What configuration are you using?
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

The emulator crashes. The configuration is the same seen in the screenshot, but also to mention the Stealth 3D 2000, Sound Blaster 16 and 32MB RAM being used.

I haven't tried the latest revision if that changed yet.

More filter WIP code, changed things into lookups

vid_voodoo.c

Code: Select all

        uint32_t u;
} rgba_u;

// leilei stuff start
#include <math.h>
int gammer[256]; // gamma correction lookup table
int thefilter[256][256]; // pixel filter, feeding from one or two
int thefilterg[256][256]; // pixel filter, feeding from one or two

void voodoo_generate_gamma(void)
{
	int g, h, i;
	float color;
	int   thiscol;

	for (g=0;g<256;g++){
		color = g / 255;
		thiscol = pow(color, 1.7) * 255; // THIS DOES NOT WORK YET
		thiscol = g; // so just use the plain color
		
		if (thiscol > 255) thiscol = 255;
		if (thiscol < 0) thiscol = 0;
		gammer[g] = thiscol;
		}
	


};

#define FILTCAP (0.075 * 255)
#define FILTCAPG (FILTCAP / 2)

int purpleline[256];
// test
int vline[600];

void voodoo_generate_filter(void)
{
	int g, h, i;
	int difference, diffg;
	float color;
	int   thiscol, thiscolg, lined;

	for (g=0;g<256;g++){			// pixel 1 
		for (h=0;h<256;h++){		// pixel 2


				difference = h - g;
				diffg = difference;

				if (difference > FILTCAP ) 	difference = FILTCAP;
				if (difference < -FILTCAP ) 	difference = -FILTCAP;

				if (diffg > FILTCAPG ) 		diffg = FILTCAPG;
				if (diffg < -FILTCAPG ) 	diffg = -FILTCAPG;

				thiscol = g + (difference/4);
				thiscolg = g + (diffg/4);

				if (thiscol < 0) 	thiscol = 0;
				if (thiscol > 255) 	thiscol = 255;

				if (thiscolg < 0) 	thiscolg = 0;
				if (thiscolg > 255) 	thiscolg = 255;

	
			thefilter[g][h] = thiscol;
			thefilterg[g][h] = thiscolg;
		}

			lined = g + 1;
			if (lined>24) lined = 24;
			purpleline[g] = lined;
	}

	int vl, a = 1;
			for (vl=0;vl<600;vl++)
			{
				a *= -1;
				if (a == 1)
					vline[vl] = 1;
				else
					vline[vl] = 0;  
					
			}	


};


// leilei stuff end

static rgba_u rgb332[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000];

Code: Select all


        int scrfilter;			/* leilei addition */
} voodoo_t;

Code: Select all

void voodoo_callback(void *p)
{
	int line = 1;
        voodoo_t *voodoo = (voodoo_t *)p;
	voodoo->scrfilter = device_get_config_int("dacfilter");


        if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
        {
                if (voodoo->line < voodoo->v_disp)
                {
                        uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32];
                        uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width];
                        int x;


			// leilei - dac screen filter, this is a messy hack with bad comment conventions
			//	a ton of it could be refactored, optimized, and vectorized
			//	this is just a rough initial implementation  by trial and error
			if (voodoo->scrfilter){
				int j, offset;
				unsigned rb[voodoo->h_disp];
				unsigned gb[voodoo->h_disp];
				unsigned bb[voodoo->h_disp];
			
				
				for (j=0;j<4;j++) // we must do 4 passes of this 
				{

		                        for (x = 0; x < voodoo->h_disp; x++)
		                        {
	
	
								int ren;
								int r1,g1,b1;	
								int r2,g2,b2;	
								int rd,gd,bd;	
					
								if (j==0){
									// initial buffer grab

							
									
								   rb[x] = src[x] & 31;
								   gb[x] = (src[x] >> 5) & 63;
								   bb[x] = (src[x] >> 11) & 31;
								   rb[x+1] = src[x+1] & 31;
								   gb[x+1] = (src[x+1] >> 5) & 63;
								   bb[x+1] = (src[x+1] >> 11) & 31;
								// add lines
								
								if (vline[voodoo->line] == 1){
									   rb[x] = purpleline[rb[x]];
									   bb[x] = purpleline[bb[x]];

									   rb[x+1] = purpleline[rb[x+1]];
									   bb[x+1] = purpleline[bb[x+1]];
									}
								
								}

						// handle offset of 4x1, which is supposed to do 3 pixels to the right then one to the left
						offset=1;
						if (x>0 && j==3) offset=-1;
	
								r1 = thefilter	[rb[x]][rb[x+offset]];
								g1 = thefilterg	[gb[x]][gb[x+offset]];
								b1 = thefilter	[bb[x]][bb[x+offset]];
			
						if (j==3){	 // final buffer write
						// TODO: Gamma

							p[x] = (gammer[r1] << 3  | gammer[g1] << 10 | gammer[b1] << 19);

						}
		
						else			// feedback filter linear passes
						{ 				

						gb[x] = g1;
						rb[x] = r1;
						bb[x] = b1;
						}


		                        }

				}

       			}
			else
			{
	                        for (x = 0; x < voodoo->h_disp; x++)
	                        {
	                                p[x] = video_16to32[src[x]];
	                        }

			}
                }
                if (voodoo->line == voodoo->v_disp)

Code: Select all

        voodoo_make_dither();

	// leilei stuff
	voodoo_generate_gamma();	// generate gamma lookup table
	voodoo_generate_filter();	// generate filter lookup tables

        
        pci_add(voodoo_pci_read, voodoo_pci_write, voodoo);

Code: Select all

                .type = CONFIG_BINARY,
                .default_int = 1
        },
        {
                .name = "dacfilter",
                .description = "Screen Filter",
                .type = CONFIG_BINARY,
                .default_int = 1
        },
        {
                .type = -1
The line adding code is a bit troublesome and bad because it kept showing green for me, so the line effect isn't correct either
Attachments
3dfxfilter2.png
3dfxfilter2.png (54.27 KiB) Viewed 56187 times
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Rev 214 made some fairly major changes, so it might help.

If it doesn't, can you run it through GDB to get a backtrace?
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

Latest revision still crashes Tomb Raider. I see two pixels on black before it does.


The Tomb Raider version i'm testing is the demo off the Diamond Monster3D disc which dates to 22 October 1996


I noticed Croc doesn't crash now though :)
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Rev 216 adds proper dithering, which might be of interest for the filter...
Freddo
Posts: 1
Joined: Wed 25 Mar, 2015 1:56 am

Re: 3DFX emulation

Post by Freddo »

This is very cool 8-) Anyone tried Redguard to see how it runs?
SA1988
Posts: 274
Joined: Wed 30 Apr, 2014 9:38 am

Re: 3DFX emulation

Post by SA1988 »

Have you guys tried Donald Duck Goin' Quackers for Windows 9x? It requires a Voodoo1 as a minimum 3D card but here it just stays black after initializing the resolutions (on PCem that is).
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

You play some truly classy games SA1988.
SA1988
Posts: 274
Joined: Wed 30 Apr, 2014 9:38 am

Re: 3DFX emulation

Post by SA1988 »

Well that game works perfectly under WinXP on VMware, but I thought of testing it on a Windows 95/98/ME guest on PCem would be quite retro :p
It originally came out in 2000 (between the releases of Windows 2000 and Windows ME to be precise) but also designed to work on Windows 95 and Windows 98 (including its Second Edition).
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Just tried Deus Ex for the hell of it, and it works! Virtually unplayable as you might expect (3-5 fps overall).
pcem_deusex1.png
pcem_deusex1.png (64.42 KiB) Viewed 55443 times
pcem_deusex2.png
pcem_deusex2.png (149.25 KiB) Viewed 55443 times
pcem_deusex3.png
pcem_deusex3.png (182.12 KiB) Viewed 55443 times
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

I notice there's additional dither in the modulated muzzleflash plane of the pistol. Voodoo has a cutoff for that i think, though i don't know what its threshold is exactly. Also I don't know if this Q3A "testing" mod will help with dither debugging, along with these screenshots to compare with.

Turok has a texture color corruption bug when you have the filter off. Occurs with ARGB4444 textures

btw you're free to include my filter into the tree. Might need some comments and formatting altered here and there, and I can't think of any improvements to make to it at this point. except for the green line bug which i'm a little lost on anyhow, and i don't know any assembly or sse intrinsics to apply and I'm not sure about the performance improvement from using lookup tables.
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Fixed Turok in rev 231. One of these days I'll make a 3dfx commit that doesn't break it...
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Fixed Deus Ex dither in rev 232. Looks like the 4x4 dither pattern isn't good for blending.
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

More filter refactoring and improvement, fixed that green line thing (needed 31 instead of 24), and work with an interleaved thing


I'm very confused at this translating a pixel shader to cpu thing. I feel like i'm not getting enough precision to do this correctly, much of the dither is retained still :S and if it isn't, it'll streak to the right too much. It's like i'm trying to do it to a 16-bit buffer, but as far as I know I have converted it to a 24-bit buffer first?


lookup gen part

Code: Select all

#include <math.h>
int gammer[256]; // gamma correction lookup table
int thefilter[256][256]; // pixel filter, feeding from one or two
int thefilterg[256][256]; // pixel filter, feeding from one or two

void voodoo_generate_gamma(void)
{
   int g, h, i;
   float color;
   int   thiscol;

   for (g=0;g<256;g++){
      color = g / 255;
      thiscol = pow(color, 1.7) * 255; // THIS DOES NOT WORK YET
      thiscol = g; // so just use the plain color
      
      if (thiscol > 255) thiscol = 255;
      if (thiscol < 0) thiscol = 0;
      gammer[g] = thiscol;
      }
   


};

#define FILTCAP 	2.0f
#define FILTCAPG (FILTCAP / 2)

int purpleline[256];
// test
int vline[600];

void voodoo_generate_filter(void)
{
   int g, h, i;
   float difference, diffg;
   float color;
   float thiscol, thiscolg, lined;

   for (g=0;g<256;g++){         // pixel 1
      for (h=0;h<256;h++){      // pixel 2


            difference = h - g;
		if  (difference < 0) difference = 0;   /* HACK: Remove ringing halo artifact */
		
            diffg = difference;

            if (difference > FILTCAP )    difference = FILTCAP;
            if (difference < -FILTCAP )    difference = -FILTCAP;

            if (diffg > FILTCAPG )       diffg = FILTCAPG;
            if (diffg < -FILTCAPG )    diffg = -FILTCAPG;

            thiscol = g + (difference / 2);
            thiscolg = g + (diffg / 2);

            if (thiscol < 0)    thiscol = 0;
            if (thiscol > 255)    thiscol = 255;

            if (thiscolg < 0)    thiscolg = 0;
            if (thiscolg > 255)    thiscolg = 255;

   
         thefilter[g][h] = thiscol;
         thefilterg[g][h] = thiscolg;
      }

         lined = g + 1;
         if (lined>31) lined = 31;
         purpleline[g] = lined;
   }

   int vl, a = 1;
         for (vl=0;vl<600;vl++)
         {
            a *= -1;
            if (a == 1)
               vline[vl] = 1;
            else
               vline[vl] = 0; 
               
         }   


};



filter/callback part

Code: Select all


#define			LOOKUP_FILTER
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

static voodoo_filterline(unsigned *fil, int column, int offset)
{
	int x;


		for (x=0; x<column-1;x++)
		{

			fil[x*3] = thefilter	[fil[x*3]]	[fil[(x+offset)*3]];
			fil[x*3+1] = thefilterg	[fil[x*3+1]]	[fil[(x+offset)*3+1]];
			fil[x*3+2] = thefilter	[fil[x*3+2]]	[fil[(x+offset)*3+2]];

		}


};

void voodoo_callback(void *p)
{
        voodoo_t *voodoo = (voodoo_t *)p;

        if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
        {
                if (voodoo->line < voodoo->v_disp)
                {
                        uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32];
                        uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width];
                        int x;

       			/* leilei - dac screen filter */
	        	if (voodoo->scrfilter)
			{
		        	int j, offset;
		        	unsigned fil[voodoo->h_disp * 3];  				/* interleaved 24-bit RGB */
		        	unsigned ail[voodoo->h_disp * 3];  				/* interleaved 24-bit RGB */
		            
				

				for (j=0;j<5;j++)
				{

						for (x = 0; x < voodoo->h_disp; x++)
						{
						   	if (j==0)						/* Grab from 16-bit buffer */
							{ 			
						 		fil[x*3] = src[x] & 31;
								fil[x*3+1] = (src[x] >> 5) & 63;
								fil[x*3+2] = (src[x] >> 11) & 31;
		
			     				       	if (vline[voodoo->line] == 1)		/* Add alternating purple lines */
								{
					                              fil[x*3] = purpleline[fil[x*3]];
					                              fil[x*3+2] = purpleline[fil[x*3+2]];
					                        }
							}
						}

					offset = 1;
						voodoo_filterline(fil, voodoo->h_disp, offset);

					


						
		            	}

		                        for (x = 0; x < voodoo->h_disp; x++)
					{
						p[x] = (fil[x*3] << 3 | fil[x*3+1] << 10 | fil[x*3+2] << 19);
					}						
		         }
		         else
		         {
		                           for (x = 0; x < voodoo->h_disp; x++)
		                           {
		                                   p[x] = video_16to32[src[x]];
		                           }
		
		         }

                }


Non-PCem code follows: my initial C implementation of the shader in Q3's texture loader which doesn't have this weird precision issue

Code: Select all

	scan = ((byte *)data);


		int passes = 5;
		int that;
#define FILTCAP (0.075 * 255)
#define FILTCAPG (FILTCAP / 2)
		for (that=0;that<passes;that++){

			for ( i = 0; i < c-1; i++ )
			{
				int ren;
				int r1,g1,b1;	
				int r2,g2,b2;	
				int rd,gd,bd;	
	
			/*  Grab Pixels to Sample From */
				r1 = scan[i*4]; 
				g1 = scan[i*4+1]; 
				b1 = scan[i*4+2]; 
				
				r2 = scan[(i+1)*4];
				g2 = scan[(i+1)*4 + 1];
				b2 = scan[(i+1)*4 + 2];
	
			/*  Find differences */
	
				rd = r2 - r1;
				gd = g2 - g1;
				bd = b2 - b1;
	
				if (rd > FILTCAP ) 	rd = FILTCAP;
				if (gd > FILTCAPG) 	gd = FILTCAPG;
				if (bd > FILTCAP ) 	bd = FILTCAP;
	
				if (rd < -FILTCAP ) 	rd = -FILTCAP;
				if (gd < -FILTCAPG) 	gd = -FILTCAPG;
				if (bd < -FILTCAP ) 	bd = -FILTCAP;
	
			/*  Add our Differences  */
	
				r1 += (rd/3);
				g1 += (gd/3);
				b1 += (bd/3);
	
			/*  Obligatory clamping part  */
				if (r1 < 0) r1 = 0;
				if (g1 < 0) g1 = 0;
				if (b1 < 0) b1 = 0;
		
				if (r1 > 255) r1 = 255;
				if (g1 > 255) g1 = 255;
				if (b1 > 255) b1 = 255;
	
				if (r2 < 0) r2 = 0;
				if (g2 < 0) g2 = 0;
				if (b2 < 0) b2 = 0;
		
				if (r2 > 255) r2 = 255;
				if (g2 > 255) g2 = 255;
				if (b2 > 255) b2 = 255;
	
	
	
			/*  Put processed image back into the buffer  */
				scan[i*4] = r1;
				scan[i*4 + 1] = g1;
				scan[i*4 + 2] =  b1;
	
			}
	
		}


BTW what's the fastest way to test Glide? As in a DOS-based Voodoo demo that loads very quickly? (all the ones I know are for V2) It takes 3 minutes for me to get from compilation to 3dfx splash with Win98+Turok
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

I used Trip (http://www.pouet.net/prod.php?which=2844) as a quick DOS-based Glide test - it has a couple of bugs but is mostly okay, and can run from a clean boot. Tomb Raider and GTA also work well for this.
It's like i'm trying to do it to a 16-bit buffer, but as far as I know I have converted it to a 24-bit buffer first?
Maybe it would help to scale the extracted R/G/B components from 0-31/63 to 0-255? I might be missing something though, I haven't actually tried to run this yet.
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

Ok i've scaled it, and also altered the buffer write to shift correctly to output so it's actually 24-bit now. The filter looks a lot closer to how i wanted it to be

There's still some precision issues though. it's not as smooth as it could be. compare a screenshot taken in Quake2 (written with 3dfxgl.dll's software filter) with a gamma 1.7'd printscreen capture on the same spot

Code: Select all

#include <math.h>
unsigned gamma_red[256]; // gamma correction lookup table for red
unsigned gamma_green[256]; // 				for green
unsigned gamma_blue[256]; // 				 for blue
static uint8_t thefilter[256][256]; // pixel filter, feeding from one or two
static uint8_t thefilterg[256][256]; // for green

void voodoo_generate_gamma(void)
{
   int g, h, i;
   float color;
   int   thiscol;
	float GAMMA_RED, GAMMA_GREEN, GAMMA_BLUE;

	/* TODO: Read from 3dfx environment variables or whatever Glide provides. Default is 1.7 */
	GAMMA_RED 	= 1.7f;
	GAMMA_GREEN 	= 1.7f;
	GAMMA_BLUE 	= 1.7f;

   for (g=0;g<256;g++){
      color = g;
      thiscol = 255 * pow(g/255, GAMMA_RED);
      
      if (thiscol > 255) thiscol = 255;     if (thiscol < 0) thiscol = 0;
      gamma_red[g] = thiscol;

      thiscol = 255 * pow(g/255, GAMMA_GREEN);
      
      if (thiscol > 255) thiscol = 255;     if (thiscol < 0) thiscol = 0;
      gamma_green[g] = thiscol;

      thiscol = 255 * pow(g/255, GAMMA_BLUE);
      
      if (thiscol > 255) thiscol = 255;     if (thiscol < 0) thiscol = 0;
      gamma_blue[g] = thiscol;
      }
   


};

#define FILTCAP 16.0f /* Needs tuning to match DAC */
#define FILTCAPG (FILTCAP / 2)

uint8_t purpleline[256];
// test
uint8_t vline[600];

void voodoo_generate_filter(void)
{
   int g, h, i;
   float difference, diffg;
   float color;
   float thiscol, thiscolg, lined;

   for (g=0;g<256;g++){         // pixel 1
      for (h=0;h<256;h++){      // pixel 2


            difference = h - g;
		
            diffg = difference;

            if (difference > FILTCAP )    difference = FILTCAP;
            if (difference < -FILTCAP )    difference = -FILTCAP;

            if (diffg > FILTCAPG )       diffg = FILTCAPG;
            if (diffg < -FILTCAPG )    diffg = -FILTCAPG;

            thiscol = g + (difference / 6); /* These two also need tuning */
            thiscolg = g + (diffg / 6);

            if (thiscol < 0)    thiscol = 0;
            if (thiscol > 255)    thiscol = 255;

            if (thiscolg < 0)    thiscolg = 0;
            if (thiscolg > 255)    thiscolg = 255;

   
         thefilter[g][h] = thiscol;
         thefilterg[g][h] = thiscolg;
      }

         lined = g + 1;
         if (lined>255) lined = 255;
         purpleline[g] = lined;
   }

   int vl, a = 1;
         for (vl=0;vl<600;vl++)
         {
            a *= -1;
            if (a == 1)
               vline[vl] = 1;
            else
               vline[vl] = 0; 
               
         }   


};

filterline stuff

Code: Select all



static voodoo_filterline(uint8_t *fil, int column, int offset)
{
	int x;
	// hopefully i hope this will lead to less cache hits or something.

		if (offset == 1)
		for (x=0; x<column-1;x++)
		{

			fil[x*3] = thefilter	[fil[x*3]]	[fil[(x+1)*3]];
			fil[x*3+1] = thefilterg	[fil[x*3+1]]	[fil[(x+1)*3+1]];
			fil[x*3+2] = thefilter	[fil[x*3+2]]	[fil[(x+1)*3+2]];

		}

		else

		for (x=1; x<column;x++)
		{

			fil[x*3] = thefilter	[fil[x*3]]	[fil[(x-1)*3]];
			fil[x*3+1] = thefilterg	[fil[x*3+1]]	[fil[(x-1)*3+1]];
			fil[x*3+2] = thefilter	[fil[x*3+2]]	[fil[(x-1)*3+2]];

		}


};

callback stuff

Code: Select all


void voodoo_callback(void *p)
{
        voodoo_t *voodoo = (voodoo_t *)p;

        if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS)
        {
                if (voodoo->line < voodoo->v_disp)
                {
                        uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32];
                        uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width];
                        int x;

       			/* leilei - dac screen filter */
	        	if (voodoo->scrfilter)
			{
		        	int j, offset;
		        	uint8_t fil[voodoo->h_disp * 3];  				/* interleaved 24-bit RGB */

				

				for (j=0;j<5;j++)
				{

						for (x = 0; x < voodoo->h_disp; x++)
						{
						   	if (j==0){					/* Grab from 16-bit buffer */
						   							/* Scale to meet */

						 		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;
		
			     				       	if (vline[voodoo->line] == 1)		/* Add alternating purple lines */
								{
					                              fil[x*3] = purpleline[fil[x*3]];
					                              fil[x*3+2] = purpleline[fil[x*3+2]];
					                        }
							}
						}

						if (j==4) offset = 1; /* One pass shifts a pixel to the left. What order, i'm not sure */
							else offset = -1;
						voodoo_filterline(fil, voodoo->h_disp, offset);
								
		            	}
		                        for (x = 0; x < voodoo->h_disp; x++)
					{
						p[x] = (fil[x*3] << 0 | fil[x*3+1] << 8 | fil[x*3+2] << 16); 

					}				
		         }
		         else
		         {
		                           for (x = 0; x < voodoo->h_disp; x++)
		                           {
		                                   p[x] = video_16to32[src[x]];
		                           }
		
		         }

                }

Attachments
pcem3dfx6.png
pcem3dfx6.png (83.82 KiB) Viewed 55201 times
Orchidsworn
Posts: 65
Joined: Sun 22 Mar, 2015 10:16 pm

Re: 3DFX emulation

Post by Orchidsworn »

Would love to see some examples of how the new mipmapping is looking. Either that or figure out how to compile this program for myself and give it a look.
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Without mipmapping:
pcem_quake_nomipmap.png
pcem_quake_nomipmap.png (332.73 KiB) Viewed 54970 times
With mipmapping:
pcem_quake_mipmap.png
pcem_quake_mipmap.png (305.95 KiB) Viewed 54970 times
Orchidsworn
Posts: 65
Joined: Sun 22 Mar, 2015 10:16 pm

Re: 3DFX emulation

Post by Orchidsworn »

now that was a quick reply love the work. Thank you sir. Can't wait for your next release.
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

For fun I tried getting my OA3 WIP working in there. It adds paletted texture extension support (same implementation as this) and processes alpha channels into a paletted alpha texture. On Voodoo Graphics it'll need a MesaFX DLL for it to work (thanks sdl :/)

However I notice that there's a bug that the alpha doesn't work. Don't know if it's the driver's end, emulation end or not. apart from that alpha bug, everything looks okay.

On an actual Voodoo2 the paletted alpha stuff works with the January 2000 3dfx GL ICD driver. I don't have an actual Voodoo Graphics to check this.
Attachments
oa3pcem5.png
oa3pcem5.png (245.78 KiB) Viewed 54866 times
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

I fixed an alpha bug in rev 243, maybe try again?
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

Doesn't fix it in the latest rev.


Here's a screenshot showing r_ext_paletted_texture 1, r_textureBits 8 on MesaFX V0.6.2.0.2 in Q3V

The paletted alpha does work on nGlide, but that pretends as a Voodoo5, and I still don't know if this artifact is actual Voodoo Graphics behavior


Another bug I was going to mention was MDK2 (4.001) getting stuck at a black screen unable to fade in after loading, however I reproduced this with a software GL ICD (SGI OpenGL 1.1) and happens in the interpreter so i'm guessing that's a CPU bug.
Attachments
pcemq3v.png
pcemq3v.png (151.98 KiB) Viewed 54820 times
User avatar
leilei
Posts: 1039
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Post by leilei »

Dunno if known or not, Half-Life 1.0.1.5 in OpenGL mode (3dfx Mini Driver) screws up similar to Spectre VR. Also the uvmapping of chrome stuff is messed up (see hand)

Latest rev with fpu copy, Pentium 120Mhz, A lot cache, 128mb, Voodoo 4mb 4mb, Win98se


I should mention I compiled with -march=amdfam10, don't know if that's a factor in anything.
Attachments
hlsven.png
hlsven.png (96.44 KiB) Viewed 54696 times
startmenu
Posts: 104
Joined: Sat 29 Nov, 2014 7:39 am

Re: 3DFX emulation

Post by startmenu »

Tomb Raider (using X:\PATCHES\3DFX\TOMB.EXE ) hangs when callin' the menu (by hittin' ESC) during the game play while the normal TOMB.EXE won't. That is, the emulation hangs but you can access the emulator's menu, of course, with no command working, including hard reset...
I also tested the \PATCHES\3DFX\TOMB.EXE under DOSBox(with 3dfx patch). It doesn't have this issue.
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Fixed in rev 253.
User avatar
SarahWalker
Site Admin
Posts: 2054
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Post by SarahWalker »

Uploaded a couple of 3DFX videos to Youtube :

Unreal : https://www.youtube.com/watch?v=EoizTnm ... e=youtu.be
Need For Speed III : https://www.youtube.com/watch?v=vxUGwwT ... e=youtu.be
amadama
Posts: 57
Joined: Mon 25 Aug, 2014 9:47 pm

Re: 3DFX emulation

Post by amadama »

That is more impressive than I expected.
What are the specs of the host machine?
Post Reply