Page 1 of 7

3DFX emulation

Posted: Sun 08 Mar, 2015 4:17 pm
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 56753 times
pcem_turok_3dfx.png
pcem_turok_3dfx.png (174.91 KiB) Viewed 56753 times
pcem_ff7_3dfx.png
pcem_ff7_3dfx.png (159.66 KiB) Viewed 56753 times
pcem_shock2_3dfx.png
pcem_shock2_3dfx.png (124.96 KiB) Viewed 56753 times
pcem_expendable_3dfx.png
pcem_expendable_3dfx.png (211.63 KiB) Viewed 56753 times
pcem_resi2_3dfx.png
pcem_resi2_3dfx.png (156.5 KiB) Viewed 56753 times

Re: 3DFX emulation

Posted: Mon 09 Mar, 2015 9:26 pm
by Bloody
Great work, looks really awesome! :)

Re: 3DFX emulation

Posted: Wed 11 Mar, 2015 12:39 am
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)

Re: 3DFX emulation

Posted: Sat 21 Mar, 2015 11:37 am
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 56363 times
When you say Tomb Raider and Croc crashed, was that the emulator crashing or the games? What configuration are you using?

Re: 3DFX emulation

Posted: Sat 21 Mar, 2015 10:39 pm
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

Re: 3DFX emulation

Posted: Sun 22 Mar, 2015 11:31 am
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?

Re: 3DFX emulation

Posted: Mon 23 Mar, 2015 1:30 am
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 :)

Re: 3DFX emulation

Posted: Mon 23 Mar, 2015 9:10 pm
by SarahWalker
Rev 216 adds proper dithering, which might be of interest for the filter...

Re: 3DFX emulation

Posted: Wed 25 Mar, 2015 9:21 am
by Freddo
This is very cool 8-) Anyone tried Redguard to see how it runs?

Re: 3DFX emulation

Posted: Wed 25 Mar, 2015 6:43 pm
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).

Re: 3DFX emulation

Posted: Wed 25 Mar, 2015 6:48 pm
by SarahWalker
You play some truly classy games SA1988.

Re: 3DFX emulation

Posted: Wed 25 Mar, 2015 6:50 pm
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).

Re: 3DFX emulation

Posted: Mon 27 Apr, 2015 7:04 pm
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 55583 times
pcem_deusex2.png
pcem_deusex2.png (149.25 KiB) Viewed 55583 times
pcem_deusex3.png
pcem_deusex3.png (182.12 KiB) Viewed 55583 times

Re: 3DFX emulation

Posted: Mon 27 Apr, 2015 10:27 pm
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.

Re: 3DFX emulation

Posted: Tue 28 Apr, 2015 7:11 pm
by SarahWalker
Fixed Turok in rev 231. One of these days I'll make a 3dfx commit that doesn't break it...

Re: 3DFX emulation

Posted: Wed 29 Apr, 2015 8:16 pm
by SarahWalker
Fixed Deus Ex dither in rev 232. Looks like the 4x4 dither pattern isn't good for blending.

Re: 3DFX emulation

Posted: Fri 01 May, 2015 8:46 pm
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

Re: 3DFX emulation

Posted: Fri 01 May, 2015 9:16 pm
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.

Re: 3DFX emulation

Posted: Sat 02 May, 2015 3:16 am
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]];
		                           }
		
		         }

                }


Re: 3DFX emulation

Posted: Mon 11 May, 2015 1:25 am
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.

Re: 3DFX emulation

Posted: Mon 11 May, 2015 7:02 pm
by SarahWalker
Without mipmapping:
pcem_quake_nomipmap.png
pcem_quake_nomipmap.png (332.73 KiB) Viewed 55110 times
With mipmapping:
pcem_quake_mipmap.png
pcem_quake_mipmap.png (305.95 KiB) Viewed 55110 times

Re: 3DFX emulation

Posted: Tue 12 May, 2015 11:38 pm
by Orchidsworn
now that was a quick reply love the work. Thank you sir. Can't wait for your next release.

Re: 3DFX emulation

Posted: Thu 14 May, 2015 7:51 am
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.

Re: 3DFX emulation

Posted: Thu 14 May, 2015 7:38 pm
by SarahWalker
I fixed an alpha bug in rev 243, maybe try again?

Re: 3DFX emulation

Posted: Thu 14 May, 2015 9:56 pm
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.

Re: 3DFX emulation

Posted: Tue 19 May, 2015 9:09 am
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.

Re: 3DFX emulation

Posted: Sun 31 May, 2015 11:41 am
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.

Re: 3DFX emulation

Posted: Sun 31 May, 2015 3:49 pm
by SarahWalker
Fixed in rev 253.

Re: 3DFX emulation

Posted: Wed 03 Jun, 2015 8:25 pm
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

Re: 3DFX emulation

Posted: Wed 03 Jun, 2015 10:58 pm
by amadama
That is more impressive than I expected.
What are the specs of the host machine?