3DFX emulation

Discussion of development and patch submission.
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

3DFX emulation

Postby SarahWalker » Sun 08 Mar, 2015 4:17 pm

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 19570 times

pcem_turok_3dfx.png
pcem_turok_3dfx.png (174.91 KiB) Viewed 19570 times

pcem_ff7_3dfx.png
pcem_ff7_3dfx.png (159.66 KiB) Viewed 19570 times

pcem_shock2_3dfx.png
pcem_shock2_3dfx.png (124.96 KiB) Viewed 19570 times

pcem_expendable_3dfx.png
pcem_expendable_3dfx.png (211.63 KiB) Viewed 19570 times

pcem_resi2_3dfx.png
pcem_resi2_3dfx.png (156.5 KiB) Viewed 19570 times
User avatar
Bloody
Posts: 4
Joined: Sun 01 Mar, 2015 7:43 am
Location: Germany

Re: 3DFX emulation

Postby Bloody » Mon 09 Mar, 2015 9:26 pm

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

Re: 3DFX emulation

Postby leilei » Wed 11 Mar, 2015 12:39 am

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 19311 times
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Sat 21 Mar, 2015 11:37 am

Quake III hang should be fixed as of rev 213.

pcem_q3_3dfx_2.png
pcem_q3_3dfx_2.png (176.96 KiB) Viewed 19180 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: 431
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Postby leilei » Sat 21 Mar, 2015 10:39 pm

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 19144 times
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Sun 22 Mar, 2015 11:31 am

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: 431
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Postby leilei » Mon 23 Mar, 2015 1:30 am

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 :)
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Mon 23 Mar, 2015 9:10 pm

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

Postby Freddo » Wed 25 Mar, 2015 9:21 am

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

Re: 3DFX emulation

Postby SA1988 » Wed 25 Mar, 2015 6:43 pm

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).
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Wed 25 Mar, 2015 6:48 pm

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

Re: 3DFX emulation

Postby SA1988 » Wed 25 Mar, 2015 6:50 pm

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).
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Mon 27 Apr, 2015 7:04 pm

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 18400 times

pcem_deusex2.png
pcem_deusex2.png (149.25 KiB) Viewed 18400 times

pcem_deusex3.png
pcem_deusex3.png (182.12 KiB) Viewed 18400 times
User avatar
leilei
Posts: 431
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Postby leilei » Mon 27 Apr, 2015 10:27 pm

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.
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Tue 28 Apr, 2015 7:11 pm

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

Re: 3DFX emulation

Postby SarahWalker » Wed 29 Apr, 2015 8:16 pm

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

Re: 3DFX emulation

Postby leilei » Fri 01 May, 2015 8:46 pm

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
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Fri 01 May, 2015 9:16 pm

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: 431
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Postby leilei » Sat 02 May, 2015 3:16 am

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 18158 times
Orchidsworn
Posts: 59
Joined: Sun 22 Mar, 2015 10:16 pm

Re: 3DFX emulation

Postby Orchidsworn » Mon 11 May, 2015 1:25 am

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.
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Mon 11 May, 2015 7:02 pm

Without mipmapping:
pcem_quake_nomipmap.png
pcem_quake_nomipmap.png (332.73 KiB) Viewed 17927 times

With mipmapping:
pcem_quake_mipmap.png
pcem_quake_mipmap.png (305.95 KiB) Viewed 17927 times
Orchidsworn
Posts: 59
Joined: Sun 22 Mar, 2015 10:16 pm

Re: 3DFX emulation

Postby Orchidsworn » Tue 12 May, 2015 11:38 pm

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

Re: 3DFX emulation

Postby leilei » Thu 14 May, 2015 7:51 am

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 17823 times
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Thu 14 May, 2015 7:38 pm

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

Re: 3DFX emulation

Postby leilei » Thu 14 May, 2015 9:56 pm

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 17777 times
User avatar
leilei
Posts: 431
Joined: Fri 25 Apr, 2014 4:47 pm

Re: 3DFX emulation

Postby leilei » Tue 19 May, 2015 9:09 am

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 17653 times
startmenu
Posts: 103
Joined: Sat 29 Nov, 2014 7:39 am

Re: 3DFX emulation

Postby startmenu » Sun 31 May, 2015 11:41 am

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.
SarahWalker
Site Admin
Posts: 1325
Joined: Thu 24 Apr, 2014 4:18 pm

Re: 3DFX emulation

Postby SarahWalker » Sun 31 May, 2015 3:49 pm

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

Re: 3DFX emulation

Postby SarahWalker » Wed 03 Jun, 2015 8:25 pm

amadama
Posts: 54
Joined: Mon 25 Aug, 2014 9:47 pm

Re: 3DFX emulation

Postby amadama » Wed 03 Jun, 2015 10:58 pm

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

Return to “Development”

Who is online

Users browsing this forum: No registered users and 2 guests