DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_emu.cpp
00001 /***************************************************************************/
00002 /*        Portion of this software comes with the following license:       */
00003 /***************************************************************************/
00004 /*
00005 
00006     Copyright Aaron Giles
00007     All rights reserved.
00008 
00009     Redistribution and use in source and binary forms, with or without
00010     modification, are permitted provided that the following conditions are
00011     met:
00012 
00013         * Redistributions of source code must retain the above copyright
00014           notice, this list of conditions and the following disclaimer.
00015         * Redistributions in binary form must reproduce the above copyright
00016           notice, this list of conditions and the following disclaimer in
00017           the documentation and/or other materials provided with the
00018           distribution.
00019         * Neither the name 'MAME' nor the names of its contributors may be
00020           used to endorse or promote products derived from this software
00021           without specific prior written permission.
00022 
00023     THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
00024     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00026     DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
00027     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00029     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00031     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032     IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033     POSSIBILITY OF SUCH DAMAGE.
00034 
00035 ****************************************************************************
00036 
00037     3dfx Voodoo Graphics SST-1/2 emulator
00038 
00039     emulator by Aaron Giles
00040 
00041     --------------------------
00042 
00043     Specs:
00044 
00045     Voodoo 1 (SST1):
00046         2,4MB frame buffer RAM
00047         1,2,4MB texture RAM
00048         50MHz clock frequency
00049         clears @ 2 pixels/clock (RGB and depth simultaneously)
00050         renders @ 1 pixel/clock
00051         64 entry PCI FIFO
00052         memory FIFO up to 65536 entries
00053 
00054     Voodoo 2:
00055         2,4MB frame buffer RAM
00056         2,4,8,16MB texture RAM
00057         90MHz clock frquency
00058         clears @ 2 pixels/clock (RGB and depth simultaneously)
00059         renders @ 1 pixel/clock
00060         ultrafast clears @ 16 pixels/clock
00061         128 entry PCI FIFO
00062         memory FIFO up to 65536 entries
00063 
00064     --------------------------
00065 
00066 
00067 iterated RGBA = 12.12 [24 bits]
00068 iterated Z    = 20.12 [32 bits]
00069 iterated W    = 18.32 [48 bits]
00070 
00071 **************************************************************************/
00072 
00073 #include <string.h>
00074 #include <stdlib.h>
00075 #include <math.h>
00076 
00077 #include "dosbox.h"
00078 #include "cross.h"
00079 
00080 #include "voodoo_emu.h"
00081 #include "voodoo_opengl.h"
00082 
00083 #include "voodoo_def.h"
00084 
00085 
00086 voodoo_state *v;
00087 
00088 
00089 #define LOG_VBLANK_SWAP         (0)
00090 #define LOG_REGISTERS           (0)
00091 #define LOG_LFB                         (0)
00092 #define LOG_TEXTURE_RAM         (0)
00093 #define LOG_RASTERIZERS         (0)
00094 
00095 
00096 /* fast dither lookup */
00097 static UINT8 dither4_lookup[256*16*2];
00098 static UINT8 dither2_lookup[256*16*2];
00099 
00100 /* fast reciprocal+log2 lookup */
00101 UINT32 voodoo_reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2];
00102 
00103 
00104 
00105 /*************************************
00106  *
00107  *  Prototypes
00108  *
00109  *************************************/
00110 
00111 /* command handlers */
00112 static void fastfill(voodoo_state *v);
00113 static void swapbuffer(voodoo_state *v, UINT32 data);
00114 static void triangle(voodoo_state *v);
00115 static void begin_triangle(voodoo_state *v);
00116 static void draw_triangle(voodoo_state *v);
00117 
00118 /* triangle helpers */
00119 static void setup_and_draw_triangle(voodoo_state *v);
00120 static void triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount);
00121 
00122 /* rasterizer management */
00123 static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo);
00124 static raster_info *find_rasterizer(voodoo_state *v, int texcount);
00125 
00126 /* generic rasterizers */
00127 static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata);
00128 
00129 
00130 /***************************************************************************
00131     RASTERIZER MANAGEMENT
00132 ***************************************************************************/
00133 
00134 void raster_generic(UINT32 TMUS, UINT32 TEXMODE0, UINT32 TEXMODE1, void *destbase,
00135                                         INT32 y, const poly_extent *extent,     const void *extradata)
00136 {
00137         const poly_extra_data *extra = (const poly_extra_data *)extradata;
00138         v = extra->state;
00139         stats_block *stats = &v->thread_stats[0];
00140         DECLARE_DITHER_POINTERS;
00141         INT32 startx = extent->startx;
00142         INT32 stopx = extent->stopx;
00143         INT32 iterr, iterg, iterb, itera;
00144         INT32 iterz;
00145         INT64 iterw, iterw0 = 0, iterw1 = 0;
00146         INT64 iters0 = 0, iters1 = 0;
00147         INT64 itert0 = 0, itert1 = 0;
00148         UINT16 *depth;
00149         UINT16 *dest;
00150         INT32 dx, dy;
00151         INT32 scry;
00152         INT32 x;
00153 
00154         /* determine the screen Y */
00155         scry = y;
00156         if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
00157                 scry = (INT32)(((int)v->fbi.yorigin - y) & 0x3ff);
00158 
00159         /* compute the dithering pointers */
00160         if (FBZMODE_ENABLE_DITHERING(v->reg[fbzMode].u))
00161         {
00162                 dither4 = &dither_matrix_4x4[(y & 3) * 4];
00163                 if (FBZMODE_DITHER_TYPE(v->reg[fbzMode].u) == 0)
00164                 {
00165                         dither = dither4;
00166                         dither_lookup = &dither4_lookup[(y & 3) << 11];
00167                 }
00168                 else
00169                 {
00170                         dither = &dither_matrix_2x2[(y & 3) * 4];
00171                         dither_lookup = &dither2_lookup[(y & 3) << 11];
00172                 }
00173         }
00174 
00175         /* apply clipping */
00176         if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u))
00177         {
00178                 INT32 tempclip;
00179 
00180                 /* Y clipping buys us the whole scanline */
00181                 if (scry < (INT32)((v->reg[clipLowYHighY].u >> 16) & 0x3ff) ||
00182                         scry >= (INT32)(v->reg[clipLowYHighY].u & 0x3ff))
00183                 {
00184                         stats->pixels_in += stopx - startx;
00185                         stats->clip_fail += stopx - startx;
00186                         return;
00187                 }
00188 
00189                 /* X clipping */
00190                 tempclip = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
00191                 if (startx < tempclip)
00192                 {
00193                         stats->pixels_in += tempclip - startx;
00194                         startx = tempclip;
00195                 }
00196                 tempclip = v->reg[clipLeftRight].u & 0x3ff;
00197                 if (stopx >= tempclip)
00198                 {
00199                         stats->pixels_in += stopx - tempclip;
00200                         stopx = tempclip - 1;
00201                 }
00202         }
00203 
00204         /* get pointers to the target buffer and depth buffer */
00205         dest = (UINT16 *)destbase + (unsigned int)scry * (unsigned long)v->fbi.rowpixels;
00206         depth = (v->fbi.auxoffs != (UINT32)(~0)) ? ((UINT16 *)(v->fbi.ram + (unsigned int)v->fbi.auxoffs) + (unsigned long)scry * (unsigned long)v->fbi.rowpixels) : NULL;
00207 
00208         /* compute the starting parameters */
00209         dx = startx - (extra->ax >> 4);
00210         dy = y - (extra->ay >> 4);
00211         iterr = extra->startr + dy * extra->drdy + dx * extra->drdx;
00212         iterg = extra->startg + dy * extra->dgdy + dx * extra->dgdx;
00213         iterb = extra->startb + dy * extra->dbdy + dx * extra->dbdx;
00214         itera = extra->starta + dy * extra->dady + dx * extra->dadx;
00215         iterz = extra->startz + dy * extra->dzdy + dx * extra->dzdx;
00216         iterw = extra->startw + dy * extra->dwdy + dx * extra->dwdx;
00217         if (TMUS >= 1)
00218         {
00219                 iterw0 = extra->startw0 + dy * extra->dw0dy + dx * extra->dw0dx;
00220                 iters0 = extra->starts0 + dy * extra->ds0dy + dx * extra->ds0dx;
00221                 itert0 = extra->startt0 + dy * extra->dt0dy + dx * extra->dt0dx;
00222         }
00223         if (TMUS >= 2)
00224         {
00225                 iterw1 = extra->startw1 + dy * extra->dw1dy + dx * extra->dw1dx;
00226                 iters1 = extra->starts1 + dy * extra->ds1dy + dx * extra->ds1dx;
00227                 itert1 = extra->startt1 + dy * extra->dt1dy + dx * extra->dt1dx;
00228         }
00229 
00230         /* loop in X */
00231         for (x = startx; x < stopx; x++)
00232         {
00233                 rgb_union iterargb;
00234                 rgb_union texel = { 0 };
00235                 rgb_union color;
00236 
00237         /* unused variable? */
00238         (void)color;
00239 
00240                 /* pixel pipeline part 1 handles depth testing and stippling */
00241                 PIXEL_PIPELINE_BEGIN(v, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw);
00242 
00243                 /* depth testing */
00244                 DEPTH_TEST(v, stats, x, v->reg[fbzMode].u);
00245 
00246                 /* run the texture pipeline on TMU1 to produce a value in texel */
00247                 /* note that they set LOD min to 8 to "disable" a TMU */
00248 
00249                 if (TMUS >= 2 && v->tmu[1].lodmin < (8 << 8))
00250                         TEXTURE_PIPELINE(&v->tmu[1], x, dither4, TEXMODE1, texel,
00251                                                                 v->tmu[1].lookup, extra->lodbase1,
00252                                                                 iters1, itert1, iterw1, texel);
00253 
00254                 /* run the texture pipeline on TMU0 to produce a final */
00255                 /* result in texel */
00256                 /* note that they set LOD min to 8 to "disable" a TMU */
00257                 if (TMUS >= 1 && v->tmu[0].lodmin < (8 << 8)) {
00258                         if (!v->send_config) {
00259                                 TEXTURE_PIPELINE(&v->tmu[0], x, dither4, TEXMODE0, texel,
00260                                                                 v->tmu[0].lookup, extra->lodbase0,
00261                                                                 iters0, itert0, iterw0, texel);
00262                         } else {        /* send config data to the frame buffer */
00263                                 texel.u=v->tmu_config;
00264                         }
00265                 }
00266 
00267                 /* colorpath pipeline selects source colors and does blending */
00268                 CLAMPED_ARGB(iterr, iterg, iterb, itera, v->reg[fbzColorPath].u, iterargb);
00269 
00270 
00271                 INT32 blendr, blendg, blendb, blenda;
00272                 rgb_union c_other;
00273                 rgb_union c_local;
00274 
00275                 /* compute c_other */
00276                 switch (FBZCP_CC_RGBSELECT(v->reg[fbzColorPath].u))
00277                 {
00278                         case 0:         /* iterated RGB */
00279                                 c_other.u = iterargb.u;
00280                                 break;
00281                         case 1:         /* texture RGB */
00282                                 c_other.u = texel.u;
00283                                 break;
00284                         case 2:         /* color1 RGB */
00285                                 c_other.u = v->reg[color1].u;
00286                                 break;
00287                         default:        /* reserved */
00288                                 c_other.u = 0;
00289                                 break;
00290                 }
00291 
00292                 /* handle chroma key */
00293                 APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, c_other);
00294 
00295                 /* compute a_other */
00296                 switch (FBZCP_CC_ASELECT(v->reg[fbzColorPath].u))
00297                 {
00298                         case 0:         /* iterated alpha */
00299                                 c_other.rgb.a = iterargb.rgb.a;
00300                                 break;
00301                         case 1:         /* texture alpha */
00302                                 c_other.rgb.a = texel.rgb.a;
00303                                 break;
00304                         case 2:         /* color1 alpha */
00305                                 c_other.rgb.a = v->reg[color1].rgb.a;
00306                                 break;
00307                         default:        /* reserved */
00308                                 c_other.rgb.a = 0;
00309                                 break;
00310                 }
00311 
00312                 /* handle alpha mask */
00313                 APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, c_other.rgb.a);
00314 
00315                 /* compute a_local */
00316                 switch (FBZCP_CCA_LOCALSELECT(v->reg[fbzColorPath].u))
00317                 {
00318                         default:
00319                         case 0:         /* iterated alpha */
00320                                 c_local.rgb.a = iterargb.rgb.a;
00321                                 break;
00322                         case 1:         /* color0 alpha */
00323                                 c_local.rgb.a = v->reg[color0].rgb.a;
00324                                 break;
00325                         case 2:         /* clamped iterated Z[27:20] */
00326                         {
00327                                 int temp;
00328                                 CLAMPED_Z(iterz, v->reg[fbzColorPath].u, temp);
00329                                 c_local.rgb.a = (UINT8)temp;
00330                                 break;
00331                         }
00332                         case 3:         /* clamped iterated W[39:32] */
00333                         {
00334                                 int temp;
00335                                 CLAMPED_W(iterw, v->reg[fbzColorPath].u, temp);                 /* Voodoo 2 only */
00336                                 c_local.rgb.a = (UINT8)temp;
00337                                 break;
00338                         }
00339                 }
00340 
00341                 /* select zero or a_other */
00342                 if (FBZCP_CCA_ZERO_OTHER(v->reg[fbzColorPath].u) == 0)
00343                         a = c_other.rgb.a;
00344                 else
00345                         a = 0;
00346 
00347                 /* subtract a_local */ 
00348                 if (FBZCP_CCA_SUB_CLOCAL(v->reg[fbzColorPath].u)) 
00349                         a -= c_local.rgb.a; 
00350                 
00351                 /* blend alpha */ 
00352                 switch (FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u)) 
00353                 { 
00354                         default: /* reserved */ 
00355                         case 0: /* 0 */ 
00356                                 blenda = 0; 
00357                                 break; 
00358                 
00359                         case 1: /* a_local */ 
00360                                 blenda = c_local.rgb.a; 
00361                                 break; 
00362                 
00363                         case 2: /* a_other */ 
00364                                 blenda = c_other.rgb.a; 
00365                                 break; 
00366                 
00367                         case 3: /* a_local */ 
00368                                 blenda = c_local.rgb.a; 
00369                                 break; 
00370                 
00371                         case 4: /* texture alpha */ 
00372                                 blenda = texel.rgb.a; 
00373                                 break; 
00374                 } 
00375                 
00376                 /* reverse the alpha blend */ 
00377                 if (!FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u)) 
00378                         blenda ^= 0xff; 
00379                 
00380                 /* do the blend */ 
00381                 a = (a * (blenda + 1)) >> 8; 
00382                 
00383                 /* add clocal or alocal to alpha */ 
00384                 if (FBZCP_CCA_ADD_ACLOCAL(v->reg[fbzColorPath].u)) 
00385                         a += c_local.rgb.a; 
00386                 
00387                 /* clamp */ 
00388                 CLAMP(a, 0x00, 0xff); 
00389                 
00390                 /* invert */ 
00391                 if (FBZCP_CCA_INVERT_OUTPUT(v->reg[fbzColorPath].u)) 
00392                         a ^= 0xff; 
00393 
00394                 /* handle alpha test */
00395                 APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, a);
00396                 
00397                 /* compute c_local */
00398                 if (FBZCP_CC_LOCALSELECT_OVERRIDE(v->reg[fbzColorPath].u) == 0)
00399                 {
00400                         if (FBZCP_CC_LOCALSELECT(v->reg[fbzColorPath].u) == 0) /* iterated RGB */
00401                                 c_local.u = iterargb.u;
00402                         else /* color0 RGB */
00403                                 c_local.u = v->reg[color0].u;
00404                 }
00405                 else
00406                 {
00407                         if (!(texel.rgb.a & 0x80)) /* iterated RGB */
00408                                 c_local.u = iterargb.u;
00409                         else /* color0 RGB */
00410                                 c_local.u = v->reg[color0].u;
00411                 } 
00412                 
00413                 /* select zero or c_other */
00414                 if (FBZCP_CC_ZERO_OTHER(v->reg[fbzColorPath].u) == 0)
00415                 {
00416                         r = c_other.rgb.r;
00417                         g = c_other.rgb.g;
00418                         b = c_other.rgb.b;
00419                 }
00420                 else
00421                         r = g = b = 0;
00422 
00423                 /* subtract c_local */
00424                 if (FBZCP_CC_SUB_CLOCAL(v->reg[fbzColorPath].u))
00425                 {
00426                         r -= c_local.rgb.r;
00427                         g -= c_local.rgb.g;
00428                         b -= c_local.rgb.b;
00429                 }
00430 
00431                 /* blend RGB */
00432                 switch (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u))
00433                 {
00434                         default:        /* reserved */
00435                         case 0:         /* 0 */
00436                                 blendr = blendg = blendb = 0;
00437                                 break;
00438                         case 1:         /* c_local */
00439                                 blendr = c_local.rgb.r;
00440                                 blendg = c_local.rgb.g;
00441                                 blendb = c_local.rgb.b;
00442                                 break;
00443                         case 2:         /* a_other */
00444                                 blendr = blendg = blendb = c_other.rgb.a;
00445                                 break;
00446                         case 3:         /* a_local */
00447                                 blendr = blendg = blendb = c_local.rgb.a;
00448                                 break;
00449                         case 4:         /* texture alpha */
00450                                 blendr = blendg = blendb = texel.rgb.a;
00451                                 break;
00452                         case 5:         /* texture RGB (Voodoo 2 only) */
00453                                 blendr = texel.rgb.r;
00454                                 blendg = texel.rgb.g;
00455                                 blendb = texel.rgb.b;
00456                                 break;
00457                 }
00458 
00459                 /* reverse the RGB blend */
00460                 if (!FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u))
00461                 {
00462                         blendr ^= 0xff;
00463                         blendg ^= 0xff;
00464                         blendb ^= 0xff;
00465                 }
00466 
00467                 /* do the blend */
00468                 r = (r * (blendr + 1)) >> 8;
00469                 g = (g * (blendg + 1)) >> 8;
00470                 b = (b * (blendb + 1)) >> 8;
00471 
00472                 /* add clocal or alocal to RGB */
00473                 switch (FBZCP_CC_ADD_ACLOCAL(v->reg[fbzColorPath].u))
00474                 {
00475                         case 3:         /* reserved */
00476                         case 0:         /* nothing */
00477                                 break;
00478                         case 1:         /* add c_local */
00479                                 r += c_local.rgb.r;
00480                                 g += c_local.rgb.g;
00481                                 b += c_local.rgb.b;
00482                                 break;
00483                         case 2:         /* add_alocal */
00484                                 r += c_local.rgb.a;
00485                                 g += c_local.rgb.a;
00486                                 b += c_local.rgb.a;
00487                                 break;
00488                 }
00489 
00490                 /* clamp */
00491                 CLAMP(r, 0x00, 0xff);
00492                 CLAMP(g, 0x00, 0xff);
00493                 CLAMP(b, 0x00, 0xff);
00494 
00495                 /* invert */
00496                 if (FBZCP_CC_INVERT_OUTPUT(v->reg[fbzColorPath].u))
00497                 {
00498                         r ^= 0xff;
00499                         g ^= 0xff;
00500                         b ^= 0xff;
00501                 }
00502 
00503                 /* pixel pipeline part 2 handles fog, alpha, and final output */
00504                 PIXEL_PIPELINE_MODIFY(v, dither, dither4, x,
00505                                                         v->reg[fbzMode].u, v->reg[fbzColorPath].u, v->reg[alphaMode].u, v->reg[fogMode].u,
00506                                                         iterz, iterw, iterargb);
00507                 PIXEL_PIPELINE_FINISH(v, dither_lookup, x, dest, depth, v->reg[fbzMode].u);
00508                 PIXEL_PIPELINE_END(stats);
00509 
00510                 /* update the iterated parameters */
00511                 iterr += extra->drdx;
00512                 iterg += extra->dgdx;
00513                 iterb += extra->dbdx;
00514                 itera += extra->dadx;
00515                 iterz += extra->dzdx;
00516                 iterw += extra->dwdx;
00517                 if (TMUS >= 1)
00518                 {
00519                         iterw0 += extra->dw0dx;
00520                         iters0 += extra->ds0dx;
00521                         itert0 += extra->dt0dx;
00522                 }
00523                 if (TMUS >= 2)
00524                 {
00525                         iterw1 += extra->dw1dx;
00526                         iters1 += extra->ds1dx;
00527                         itert1 += extra->dt1dx;
00528                 }
00529         }
00530 }
00531 
00532 
00533 /***************************************************************************
00534     RASTERIZER MANAGEMENT
00535 ***************************************************************************/
00536 
00537 void raster_generic_0tmu(void *destbase, INT32 y, const poly_extent *extent, const void *extradata) {
00538         raster_generic(0, 0, 0, destbase, y, extent, extradata);
00539 }
00540 
00541 void raster_generic_1tmu(void *destbase, INT32 y, const poly_extent *extent, const void *extradata) {
00542         raster_generic(1, v->tmu[0].reg[textureMode].u, 0, destbase, y, extent, extradata);
00543 }
00544 
00545 void raster_generic_2tmu(void *destbase, INT32 y, const poly_extent *extent, const void *extradata) {
00546         raster_generic(2, v->tmu[0].reg[textureMode].u, v->tmu[1].reg[textureMode].u, destbase, y, extent, extradata);
00547 }
00548 
00549 
00550 
00551 /*************************************
00552  *
00553  *  Common initialization
00554  *
00555  *************************************/
00556 
00557 void init_fbi(voodoo_state *v, fbi_state *f, int fbmem)
00558 {
00559         if (fbmem <= 1) E_Exit("VOODOO: invalid frame buffer memory size requested");
00560         /* allocate frame buffer RAM and set pointers */
00561         f->ram = (UINT8*)malloc((size_t)fbmem);
00562         f->mask = (UINT32)(fbmem - 1);
00563         f->rgboffs[0] = f->rgboffs[1] = f->rgboffs[2] = 0;
00564         f->auxoffs = (UINT32)(~0);
00565 
00566         /* default to 0x0 */
00567         f->frontbuf = 0;
00568         f->backbuf = 1;
00569         f->width = 640;
00570         f->height = 480;
00571 //      f->xoffs = 0;
00572 //      f->yoffs = 0;
00573 
00574 //      f->vsyncscan = 0;
00575 
00576         /* init the pens */
00577 /*      for (UINT8 pen = 0; pen < 32; pen++)
00578                 v->fbi.clut[pen] = MAKE_ARGB(pen, pal5bit(pen), pal5bit(pen), pal5bit(pen));
00579         v->fbi.clut[32] = MAKE_ARGB(32,0xff,0xff,0xff); */
00580 
00581         /* allocate a VBLANK timer */
00582         f->vblank = false;
00583 
00584         /* initialize the memory FIFO */
00585         f->fifo.size = 0;
00586 
00587         /* set the fog delta mask */
00588         f->fogdelta_mask = (v->type < VOODOO_2) ? 0xff : 0xfc;
00589 
00590         f->yorigin = 0;
00591 
00592         f->sverts = 0;
00593 
00594         memset(&f->lfb_stats, 0, sizeof(f->lfb_stats));
00595         memset(&f->fogblend, 0, sizeof(f->fogblend));
00596         memset(&f->fogdelta, 0, sizeof(f->fogdelta));
00597 }
00598 
00599 
00600 void init_tmu_shared(tmu_shared_state *s)
00601 {
00602         int val;
00603 
00604         /* build static 8-bit texel tables */
00605         for (val = 0; val < 256; val++)
00606         {
00607                 int r, g, b, a;
00608 
00609                 /* 8-bit RGB (3-3-2) */
00610                 EXTRACT_332_TO_888(val, r, g, b);
00611                 s->rgb332[val] = MAKE_ARGB(0xff, r, g, b);
00612 
00613                 /* 8-bit alpha */
00614                 s->alpha8[val] = MAKE_ARGB(val, val, val, val);
00615 
00616                 /* 8-bit intensity */
00617                 s->int8[val] = MAKE_ARGB(0xff, val, val, val);
00618 
00619                 /* 8-bit alpha, intensity */
00620                 a = ((val >> 0) & 0xf0) | ((val >> 4) & 0x0f);
00621                 r = ((val << 4) & 0xf0) | ((val << 0) & 0x0f);
00622                 s->ai44[val] = MAKE_ARGB(a, r, r, r);
00623         }
00624 
00625         /* build static 16-bit texel tables */
00626         for (val = 0; val < 65536; val++)
00627         {
00628                 int r, g, b, a;
00629 
00630                 /* table 10 = 16-bit RGB (5-6-5) */
00631                 EXTRACT_565_TO_888(val, r, g, b);
00632                 s->rgb565[val] = MAKE_ARGB(0xff, r, g, b);
00633 
00634                 /* table 11 = 16 ARGB (1-5-5-5) */
00635                 EXTRACT_1555_TO_8888(val, a, r, g, b);
00636                 s->argb1555[val] = MAKE_ARGB(a, r, g, b);
00637 
00638                 /* table 12 = 16-bit ARGB (4-4-4-4) */
00639                 EXTRACT_4444_TO_8888(val, a, r, g, b);
00640                 s->argb4444[val] = MAKE_ARGB(a, r, g, b);
00641         }
00642 }
00643 
00644 
00645 void init_tmu(voodoo_state *v, tmu_state *t, voodoo_reg *reg, int tmem)
00646 {
00647         if (tmem <= 1) E_Exit("VOODOO: invalid texture buffer memory size requested");
00648         /* allocate texture RAM */
00649         t->ram = (UINT8*)malloc((size_t)tmem);
00650         t->mask = (UINT32)(tmem - 1);
00651         t->reg = reg;
00652         t->regdirty = true;
00653         t->bilinear_mask = (v->type >= VOODOO_2) ? 0xff : 0xf0;
00654 
00655         /* mark the NCC tables dirty and configure their registers */
00656         t->ncc[0].dirty = t->ncc[1].dirty = true;
00657         t->ncc[0].reg = &t->reg[nccTable+0];
00658         t->ncc[1].reg = &t->reg[nccTable+12];
00659 
00660         /* create pointers to all the tables */
00661         t->texel[0] = v->tmushare.rgb332;
00662         t->texel[1] = t->ncc[0].texel;
00663         t->texel[2] = v->tmushare.alpha8;
00664         t->texel[3] = v->tmushare.int8;
00665         t->texel[4] = v->tmushare.ai44;
00666         t->texel[5] = t->palette;
00667         t->texel[6] = (v->type >= VOODOO_2) ? t->palettea : NULL;
00668         t->texel[7] = NULL;
00669         t->texel[8] = v->tmushare.rgb332;
00670         t->texel[9] = t->ncc[0].texel;
00671         t->texel[10] = v->tmushare.rgb565;
00672         t->texel[11] = v->tmushare.argb1555;
00673         t->texel[12] = v->tmushare.argb4444;
00674         t->texel[13] = v->tmushare.int8;
00675         t->texel[14] = t->palette;
00676         t->texel[15] = NULL;
00677         t->lookup = t->texel[0];
00678 
00679         /* attach the palette to NCC table 0 */
00680         t->ncc[0].palette = t->palette;
00681         if (v->type >= VOODOO_2)
00682                 t->ncc[0].palettea = t->palettea;
00683 
00684         /* set up texture address calculations */
00685         t->texaddr_mask = 0x0fffff;
00686         t->texaddr_shift = 3;
00687 
00688         t->lodmin=0;
00689         t->lodmax=0;
00690 }
00691 
00692 
00693 /*************************************
00694  *
00695  *  VBLANK management
00696  *
00697  *************************************/
00698 
00699 void voodoo_swap_buffers(voodoo_state *v)
00700 {
00701 //      if (LOG_VBLANK_SWAP) LOG(LOG_VOODOO,LOG_WARN)("--- swap_buffers @ %d\n", video_screen_get_vpos(v->screen));
00702 
00703         if (v->ogl && v->active) {
00704                 voodoo_ogl_swap_buffer();
00705                 return;
00706         }
00707 
00708         /* keep a history of swap intervals */
00709         v->reg[fbiSwapHistory].u = (v->reg[fbiSwapHistory].u << 4);
00710 
00711         /* rotate the buffers */
00712         if (v->type < VOODOO_2 || !v->fbi.vblank_dont_swap)
00713         {
00714                 if (v->fbi.rgboffs[2] == (UINT32)(~0))
00715                 {
00716                         v->fbi.frontbuf = (UINT8)(1 - v->fbi.frontbuf);
00717                         v->fbi.backbuf = (UINT8)(1 - v->fbi.frontbuf);
00718                 }
00719                 else
00720                 {
00721                         v->fbi.frontbuf = (v->fbi.frontbuf + 1) % 3;
00722                         v->fbi.backbuf = (v->fbi.frontbuf + 1) % 3;
00723                 }
00724         }
00725 }
00726 
00727 
00728 
00729 /*************************************
00730  *
00731  *  Chip reset
00732  *
00733  *************************************/
00734 
00735 void reset_counters(voodoo_state *v)
00736 {
00737         v->reg[fbiPixelsIn].u = 0;
00738         v->reg[fbiChromaFail].u = 0;
00739         v->reg[fbiZfuncFail].u = 0;
00740         v->reg[fbiAfuncFail].u = 0;
00741         v->reg[fbiPixelsOut].u = 0;
00742 }
00743 
00744 
00745 void soft_reset(voodoo_state *v)
00746 {
00747         reset_counters(v);
00748         v->reg[fbiTrianglesOut].u = 0;
00749 }
00750 
00751 
00752 
00753 /*************************************
00754  *
00755  *  Recompute video memory layout
00756  *
00757  *************************************/
00758 
00759 void recompute_video_memory(voodoo_state *v)
00760 {
00761         UINT32 buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(v->reg[fbiInit2].u);
00762         UINT32 fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(v->reg[fbiInit4].u);
00763         UINT32 fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(v->reg[fbiInit4].u);
00764         UINT32 memory_config;
00765         int buf;
00766 
00767         /* memory config is determined differently between V1 and V2 */
00768         memory_config = FBIINIT2_ENABLE_TRIPLE_BUF(v->reg[fbiInit2].u);
00769         if (v->type == VOODOO_2 && memory_config == 0)
00770                 memory_config = FBIINIT5_BUFFER_ALLOCATION(v->reg[fbiInit5].u);
00771 
00772         /* tiles are 64x16/32; x_tiles specifies how many half-tiles */
00773         v->fbi.tile_width = (v->type < VOODOO_2) ? 64 : 32;
00774         v->fbi.tile_height = (v->type < VOODOO_2) ? 16 : 32;
00775         v->fbi.x_tiles = FBIINIT1_X_VIDEO_TILES(v->reg[fbiInit1].u);
00776         if (v->type == VOODOO_2)
00777         {
00778                 v->fbi.x_tiles = (v->fbi.x_tiles << 1) |
00779                                                 (FBIINIT1_X_VIDEO_TILES_BIT5(v->reg[fbiInit1].u) << 5) |
00780                                                 (FBIINIT6_X_VIDEO_TILES_BIT0(v->reg[fbiInit6].u));
00781         }
00782         v->fbi.rowpixels = v->fbi.tile_width * v->fbi.x_tiles;
00783 
00784 //  logerror("VOODOO.%d.VIDMEM: buffer_pages=%X  fifo=%X-%X  tiles=%X  rowpix=%d\n", v->index, buffer_pages, fifo_start_page, fifo_last_page, v->fbi.x_tiles, v->fbi.rowpixels);
00785 
00786         /* first RGB buffer always starts at 0 */
00787         v->fbi.rgboffs[0] = 0;
00788 
00789         /* second RGB buffer starts immediately afterwards */
00790         v->fbi.rgboffs[1] = buffer_pages * 0x1000;
00791 
00792         /* remaining buffers are based on the config */
00793         switch (memory_config)
00794         {
00795         case 3: /* reserved */
00796                 LOG(LOG_VOODOO,LOG_WARN)("VOODOO.ERROR:Unexpected memory configuration in recompute_video_memory!\n");
00797 
00798         case 0: /* 2 color buffers, 1 aux buffer */
00799                 v->fbi.rgboffs[2] = (UINT32)(~0);
00800                 v->fbi.auxoffs = 2 * buffer_pages * 0x1000;
00801                 break;
00802 
00803         case 1: /* 3 color buffers, 0 aux buffers */
00804                 v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
00805                 v->fbi.auxoffs = (UINT32)(~0);
00806                 break;
00807 
00808         case 2: /* 3 color buffers, 1 aux buffers */
00809                 v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000;
00810                 v->fbi.auxoffs = 3 * buffer_pages * 0x1000;
00811                 break;
00812         }
00813 
00814         /* clamp the RGB buffers to video memory */
00815         for (buf = 0; buf < 3; buf++)
00816                 if (v->fbi.rgboffs[buf] != (UINT32)(~0) && v->fbi.rgboffs[buf] > v->fbi.mask)
00817                         v->fbi.rgboffs[buf] = v->fbi.mask;
00818 
00819         /* clamp the aux buffer to video memory */
00820         if (v->fbi.auxoffs != (UINT32)(~0) && v->fbi.auxoffs > v->fbi.mask)
00821                 v->fbi.auxoffs = v->fbi.mask;
00822 
00823         /* compute the memory FIFO location and size */
00824         if (fifo_last_page > v->fbi.mask / 0x1000)
00825                 fifo_last_page = v->fbi.mask / 0x1000;
00826 
00827         /* is it valid and enabled? */
00828         if (fifo_start_page <= fifo_last_page && FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u))
00829         {
00830                 v->fbi.fifo.size = (INT32)(((unsigned int)fifo_last_page + 1u - (unsigned int)fifo_start_page) * 0x1000u / 4u);
00831                 if (v->fbi.fifo.size > 65536*2)
00832                         v->fbi.fifo.size = 65536*2;
00833         }
00834         else    /* if not, disable the FIFO */
00835         {
00836                 v->fbi.fifo.size = 0;
00837         }
00838 
00839         /* reset our front/back buffers if they are out of range */
00840         if (v->fbi.rgboffs[2] == (UINT32)(~0))
00841         {
00842                 if (v->fbi.frontbuf == 2)
00843                         v->fbi.frontbuf = 0;
00844                 if (v->fbi.backbuf == 2)
00845                         v->fbi.backbuf = 0;
00846         }
00847 }
00848 
00849 
00850 
00851 /*************************************
00852  *
00853  *  NCC table management
00854  *
00855  *************************************/
00856 
00857 static bool palette_changed = false;
00858 
00859 void ncc_table_write(ncc_table *n, UINT32 regnum, UINT32 data)
00860 {
00861         /* I/Q entries reference the palette if the high bit is set */
00862         if (regnum >= 4 && (data & 0x80000000) && n->palette)
00863         {
00864                 UINT32 index = ((data >> 23) & 0xfe) | (regnum & 1);
00865 
00866                 rgb_t palette_entry = 0xff000000 | data;
00867 
00868                 if (n->palette[index] != palette_entry) {
00869                         /* set the ARGB for this palette index */
00870                         n->palette[index] = palette_entry;
00871                         palette_changed = true;
00872                 }
00873 
00874                 /* if we have an ARGB palette as well, compute its value */
00875                 if (n->palettea)
00876                 {
00877                         UINT32 a = ((data >> 16) & 0xfc) | ((data >> 22) & 0x03);
00878                         UINT32 r = ((data >> 10) & 0xfc) | ((data >> 16) & 0x03);
00879                         UINT32 g = ((data >>  4) & 0xfc) | ((data >> 10) & 0x03);
00880                         UINT32 b = ((data <<  2) & 0xfc) | ((data >>  4) & 0x03);
00881                         n->palettea[index] = MAKE_ARGB(a, r, g, b);
00882                 }
00883 
00884                 /* this doesn't dirty the table or go to the registers, so bail */
00885                 return;
00886         }
00887 
00888         /* if the register matches, don't update */
00889         if (data == n->reg[regnum].u)
00890                 return;
00891         n->reg[regnum].u = data;
00892 
00893         /* first four entries are packed Y values */
00894         if (regnum < 4)
00895         {
00896                 regnum *= 4;
00897                 n->y[regnum+0] = (INT32)(data >>  0) & 0xff;
00898                 n->y[regnum+1] = (INT32)(data >>  8) & 0xff;
00899                 n->y[regnum+2] = (INT32)(data >> 16) & 0xff;
00900                 n->y[regnum+3] = (INT32)(data >> 24) & 0xff;
00901         }
00902 
00903         /* the second four entries are the I RGB values */
00904         else if (regnum < 8)
00905         {
00906                 regnum &= 3;
00907                 n->ir[regnum] = (INT32)(data <<  5) >> 23;
00908                 n->ig[regnum] = (INT32)(data << 14) >> 23;
00909                 n->ib[regnum] = (INT32)(data << 23) >> 23;
00910         }
00911 
00912         /* the final four entries are the Q RGB values */
00913         else
00914         {
00915                 regnum &= 3;
00916                 n->qr[regnum] = (INT32)(data <<  5) >> 23;
00917                 n->qg[regnum] = (INT32)(data << 14) >> 23;
00918                 n->qb[regnum] = (INT32)(data << 23) >> 23;
00919         }
00920 
00921         /* mark the table dirty */
00922         n->dirty = true;
00923 }
00924 
00925 
00926 void ncc_table_update(ncc_table *n)
00927 {
00928         /* generate all 256 possibilities */
00929         for (int i = 0; i < 256; i++)
00930         {
00931                 int vi = (i >> 2) & 0x03;
00932                 int vq = (i >> 0) & 0x03;
00933 
00934                 /* start with the intensity */
00935                 int r, g, b;
00936                 r = g = b = n->y[(i >> 4) & 0x0f];
00937 
00938                 /* add the coloring */
00939                 r += n->ir[vi] + n->qr[vq];
00940                 g += n->ig[vi] + n->qg[vq];
00941                 b += n->ib[vi] + n->qb[vq];
00942 
00943                 /* clamp */
00944                 CLAMP(r, 0, 255);
00945                 CLAMP(g, 0, 255);
00946                 CLAMP(b, 0, 255);
00947 
00948                 /* fill in the table */
00949                 n->texel[i] = MAKE_ARGB(0xff, r, g, b);
00950         }
00951 
00952         /* no longer dirty */
00953         n->dirty = false;
00954 }
00955 
00956 
00957 
00958 /*************************************
00959  *
00960  *  Faux DAC implementation
00961  *
00962  *************************************/
00963 
00964 void dacdata_w(dac_state *d, UINT8 regnum, UINT8 data)
00965 {
00966         d->reg[regnum] = data;
00967 }
00968 
00969 
00970 void dacdata_r(dac_state *d, UINT8 regnum)
00971 {
00972         UINT8 result = 0xff;
00973 
00974         /* switch off the DAC register requested */
00975         switch (regnum)
00976         {
00977                 case 5:
00978                         /* this is just to make startup happy */
00979                         switch (d->reg[7])
00980                         {
00981                                 case 0x01:      result = 0x55; break;
00982                                 case 0x07:      result = 0x71; break;
00983                                 case 0x0b:      result = 0x79; break;
00984                         }
00985                         break;
00986 
00987                 default:
00988                         result = d->reg[regnum];
00989                         break;
00990         }
00991 
00992         /* remember the read result; it is fetched elsewhere */
00993         d->read_result = result;
00994 }
00995 
00996 
00997 
00998 /*************************************
00999  *
01000  *  Texuture parameter computation
01001  *
01002  *************************************/
01003 
01004 void recompute_texture_params(tmu_state *t)
01005 {
01006         int bppscale;
01007         UINT32 base;
01008         int lod;
01009 
01010         /* extract LOD parameters */
01011         t->lodmin = (INT32)TEXLOD_LODMIN(t->reg[tLOD].u) << 6;
01012         t->lodmax = (INT32)TEXLOD_LODMAX(t->reg[tLOD].u) << 6;
01013         t->lodbias = (INT8)(TEXLOD_LODBIAS(t->reg[tLOD].u) << 2) << 4;
01014 
01015         /* determine which LODs are present */
01016         t->lodmask = 0x1ff;
01017         if (TEXLOD_LOD_TSPLIT(t->reg[tLOD].u))
01018         {
01019                 if (!TEXLOD_LOD_ODD(t->reg[tLOD].u))
01020                         t->lodmask = 0x155;
01021                 else
01022                         t->lodmask = 0x0aa;
01023         }
01024 
01025         /* determine base texture width/height */
01026         t->wmask = t->hmask = 0xff;
01027         if (TEXLOD_LOD_S_IS_WIDER(t->reg[tLOD].u))
01028                 t->hmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
01029         else
01030                 t->wmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
01031 
01032         /* determine the bpp of the texture */
01033         bppscale = (int)TEXMODE_FORMAT(t->reg[textureMode].u) >> 3;
01034 
01035         /* start with the base of LOD 0 */
01036         if (t->texaddr_shift == 0 && (t->reg[texBaseAddr].u & 1))
01037                 LOG(LOG_VOODOO,LOG_WARN)("Tiled texture\n");
01038         base = (t->reg[texBaseAddr].u & t->texaddr_mask) << t->texaddr_shift;
01039         t->lodoffset[0] = base & t->mask;
01040 
01041         /* LODs 1-3 are different depending on whether we are in multitex mode */
01042         /* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */
01043         /* they want multitex mode when they really don't -- disable for now */
01044         if (0)//TEXLOD_TMULTIBASEADDR(t->reg[tLOD].u))
01045         {
01046                 base = (t->reg[texBaseAddr_1].u & t->texaddr_mask) << t->texaddr_shift;
01047                 t->lodoffset[1] = base & t->mask;
01048                 base = (t->reg[texBaseAddr_2].u & t->texaddr_mask) << t->texaddr_shift;
01049                 t->lodoffset[2] = base & t->mask;
01050                 base = (t->reg[texBaseAddr_3_8].u & t->texaddr_mask) << t->texaddr_shift;
01051                 t->lodoffset[3] = base & t->mask;
01052         }
01053         else
01054         {
01055                 if (t->lodmask & (1 << 0))
01056                         base += (((t->wmask >> 0) + 1) * ((t->hmask >> 0) + 1)) << bppscale;
01057                 t->lodoffset[1] = base & t->mask;
01058                 if (t->lodmask & (1 << 1))
01059                         base += (((t->wmask >> 1) + 1) * ((t->hmask >> 1) + 1)) << bppscale;
01060                 t->lodoffset[2] = base & t->mask;
01061                 if (t->lodmask & (1 << 2))
01062                         base += (((t->wmask >> 2) + 1) * ((t->hmask >> 2) + 1)) << bppscale;
01063                 t->lodoffset[3] = base & t->mask;
01064         }
01065 
01066         /* remaining LODs make sense */
01067         for (lod = 4; lod <= 8; lod++)
01068         {
01069                 if (t->lodmask & (1u << (lod - 1)))
01070                 {
01071                         UINT32 size = ((t->wmask >> (lod - 1)) + 1) * ((t->hmask >> (lod - 1)) + 1);
01072                         if (size < 4) size = 4;
01073                         base += size << bppscale;
01074                 }
01075                 t->lodoffset[lod] = base & t->mask;
01076         }
01077 
01078         /* set the NCC lookup appropriately */
01079         t->texel[1] = t->texel[9] = t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)].texel;
01080 
01081         /* pick the lookup table */
01082         t->lookup = t->texel[TEXMODE_FORMAT(t->reg[textureMode].u)];
01083 
01084         /* compute the detail parameters */
01085         t->detailmax = TEXDETAIL_DETAIL_MAX(t->reg[tDetail].u);
01086         t->detailbias = (INT8)(TEXDETAIL_DETAIL_BIAS(t->reg[tDetail].u) << 2) << 6;
01087         t->detailscale = TEXDETAIL_DETAIL_SCALE(t->reg[tDetail].u);
01088 
01089         /* no longer dirty */
01090         t->regdirty = false;
01091 
01092         /* check for separate RGBA filtering */
01093         if (TEXDETAIL_SEPARATE_RGBA_FILTER(t->reg[tDetail].u))
01094                 E_Exit("Separate RGBA filters!");
01095 }
01096 
01097 
01098 INLINE INT32 prepare_tmu(tmu_state *t)
01099 {
01100         INT64 texdx, texdy;
01101         INT32 lodbase;
01102 
01103         /* if the texture parameters are dirty, update them */
01104         if (t->regdirty)
01105         {
01106                 recompute_texture_params(t);
01107 
01108                 /* ensure that the NCC tables are up to date */
01109                 if ((TEXMODE_FORMAT(t->reg[textureMode].u) & 7) == 1)
01110                 {
01111                         ncc_table *n = &t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)];
01112                         t->texel[1] = t->texel[9] = n->texel;
01113                         if (n->dirty)
01114                                 ncc_table_update(n);
01115                 }
01116         }
01117 
01118         /* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */
01119         texdx = (INT64)(t->dsdx >> 14) * (INT64)(t->dsdx >> 14) + (INT64)(t->dtdx >> 14) * (INT64)(t->dtdx >> 14);
01120         texdy = (INT64)(t->dsdy >> 14) * (INT64)(t->dsdy >> 14) + (INT64)(t->dtdy >> 14) * (INT64)(t->dtdy >> 14);
01121 
01122         /* pick whichever is larger and shift off some high bits -> 28.20 */
01123         if (texdx < texdy)
01124                 texdx = texdy;
01125         texdx >>= 16;
01126 
01127         /* use our fast reciprocal/log on this value; it expects input as a */
01128         /* 16.32 number, and returns the log of the reciprocal, so we have to */
01129         /* adjust the result: negative to get the log of the original value */
01130         /* plus 12 to account for the extra exponent, and divided by 2 to */
01131         /* get the log of the square root of texdx */
01132         (void)fast_reciplog(texdx, &lodbase);
01133         return (-lodbase + (12 << 8)) / 2;
01134 }
01135 
01136 
01137 INLINE INT32 round_coordinate(float value)
01138 {
01139         INT32 result = (INT32)floor(value);
01140         return result + (value - (float)result > 0.5f);
01141 }
01142 
01143 void poly_render_triangle(void *dest, poly_draw_scanline_func callback, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, poly_extra_data *extra)
01144 {
01145         float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3;
01146         const poly_vertex *tv;
01147         INT32 curscan, scaninc=1;
01148 
01149         INT32 v1yclip, v3yclip;
01150         INT32 v1y, v3y;//, v1x;
01151 
01152         /* first sort by Y */
01153         if (v2->y < v1->y)
01154         {
01155                 tv = v1;
01156                 v1 = v2;
01157                 v2 = tv;
01158         }
01159         if (v3->y < v2->y)
01160         {
01161                 tv = v2;
01162                 v2 = v3;
01163                 v3 = tv;
01164                 if (v2->y < v1->y)
01165                 {
01166                         tv = v1;
01167                         v1 = v2;
01168                         v2 = tv;
01169                 }
01170         }
01171 
01172         /* compute some integral X/Y vertex values */
01173 //      v1x = round_coordinate(v1->x);
01174         v1y = round_coordinate(v1->y);
01175         v3y = round_coordinate(v3->y);
01176 
01177         /* clip coordinates */
01178         v1yclip = v1y;
01179         v3yclip = v3y;// + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
01180         if (v3yclip - v1yclip <= 0)
01181                 return;
01182 
01183         /* compute the slopes for each portion of the triangle */
01184         dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y);
01185         dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y);
01186         dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y);
01187 
01188         poly_extent *extent = new poly_extent;
01189         int extnum=0;
01190         for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
01191         {
01192                 {
01193                         float fully = (float)(curscan + extnum) + 0.5f;
01194                         float startx = v1->x + (fully - v1->y) * dxdy_v1v3;
01195                         float stopx;
01196                         INT32 istartx, istopx;
01197 
01198                         /* compute the ending X based on which part of the triangle we're in */
01199                         if (fully < v2->y)
01200                                 stopx = v1->x + (fully - v1->y) * dxdy_v1v2;
01201                         else
01202                                 stopx = v2->x + (fully - v2->y) * dxdy_v2v3;
01203 
01204                         /* clamp to full pixels */
01205                         istartx = round_coordinate(startx);
01206                         istopx = round_coordinate(stopx);
01207 
01208                         /* force start < stop */
01209                         if (istartx > istopx)
01210                         {
01211                                 INT32 temp = istartx;
01212                                 istartx = istopx;
01213                                 istopx = temp;
01214                         }
01215 
01216                         /* set the extent and update the total pixel count */
01217                         if (istartx >= istopx)
01218                                 istartx = istopx = 0;
01219 
01220                         extent->startx = istartx;
01221                         extent->stopx = istopx;
01222                         (callback)(dest,curscan,extent,extra);
01223                 }
01224         }
01225 
01226         delete extent;
01227 }
01228 
01229 
01230 
01231 void poly_render_triangle_custom(void *dest, int startscanline, int numscanlines, const poly_extent *extents, poly_extra_data *extra)
01232 {
01233         INT32 curscan, scaninc;
01234         INT32 v1yclip, v3yclip;
01235 
01236         v1yclip = startscanline;
01237         v3yclip = startscanline + numscanlines;
01238 
01239         if (v3yclip - v1yclip <= 0)
01240                 return;
01241 
01242         for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
01243         {
01244                 tri_work_unit *unit = new tri_work_unit;
01245                 int extnum=0;
01246 
01247                 /* determine how much to advance to hit the next bucket */
01248                 scaninc = 1;
01249 
01250                 const poly_extent *extent = &extents[(curscan + extnum) - startscanline];
01251                 INT32 istartx = extent->startx, istopx = extent->stopx;
01252 
01253                 /* force start < stop */
01254                 if (istartx > istopx)
01255                 {
01256                         INT32 temp = istartx;
01257                         istartx = istopx;
01258                         istopx = temp;
01259                 }
01260 
01261                 /* set the extent and update the total pixel count */
01262                 unit->extent[extnum].startx = (INT16)istartx;
01263                 unit->extent[extnum].stopx = (INT16)istopx;
01264                 raster_fastfill(dest,curscan,extent,extra);
01265                 delete unit;
01266         }
01267 }
01268 
01269 
01270 
01271 /*************************************
01272  *
01273  *  Statistics management
01274  *
01275  *************************************/
01276 
01277 static void accumulate_statistics(voodoo_state *v, const stats_block *stats)
01278 {
01279         /* apply internal voodoo statistics */
01280         v->reg[fbiPixelsIn].u += (UINT32)stats->pixels_in;
01281         v->reg[fbiPixelsOut].u += (UINT32)stats->pixels_out;
01282         v->reg[fbiChromaFail].u += (UINT32)stats->chroma_fail;
01283         v->reg[fbiZfuncFail].u += (UINT32)stats->zfunc_fail;
01284         v->reg[fbiAfuncFail].u += (UINT32)stats->afunc_fail;
01285 }
01286 
01287 static void update_statistics(voodoo_state *v, bool accumulate)
01288 {
01289         /* accumulate/reset statistics from all units */
01290         if (accumulate)
01291                 accumulate_statistics(v, &v->thread_stats[0]);
01292         memset(&v->thread_stats[0], 0, sizeof(v->thread_stats[0]));
01293 
01294         /* accumulate/reset statistics from the LFB */
01295         if (accumulate)
01296                 accumulate_statistics(v, &v->fbi.lfb_stats);
01297         memset(&v->fbi.lfb_stats, 0, sizeof(v->fbi.lfb_stats));
01298 }
01299 
01300 
01301 
01302 /*************************************
01303  *
01304  *  Voodoo register writes
01305  *
01306  *************************************/
01307 
01308 void register_w(UINT32 offset, UINT32 data) {
01309 //      voodoo_reg reg;
01310         UINT32 regnum;
01311         UINT32 chips   = (offset>>8) & 0xf;
01312 //      reg.u = data;
01313 
01314         INT64 data64;
01315 
01316 //      LOG(LOG_VOODOO,LOG_WARN)("V3D:WR chip %x reg %x value %08x(%s)", chips, regnum<<2, data, voodoo_reg_name[regnum]);
01317 
01318         if (chips == 0)
01319                 chips = 0xf;
01320         chips &= v->chipmask;
01321 
01322         /* the first 64 registers can be aliased differently */
01323         if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
01324                 regnum = register_alias_map[offset & 0x3f];
01325         else
01326                 regnum = offset & 0xff;
01327 
01328         /* first make sure this register is readable */
01329         if (!(v->regaccess[regnum] & REGISTER_WRITE))
01330         {
01331                 if (regnum <= 0xe0) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.ERROR:Invalid attempt to write %s\n", v->regnames[regnum]);
01332                 else LOG(LOG_VOODOO,LOG_WARN)("VOODOO.ERROR:Invalid attempt to write #%x\n", regnum);
01333                 return;
01334         }
01335 
01336         /* switch off the register */
01337         switch (regnum)
01338         {
01339                 /* Vertex data is 12.4 formatted fixed point */
01340                 case fvertexAx:
01341                         data = (UINT32)float_to_int32(data, 4);
01342                 case vertexAx:
01343                         if (chips & 1) v->fbi.ax = (INT16)(data&0xffff);
01344                         break;
01345 
01346                 case fvertexAy:
01347                         data = (UINT32)float_to_int32(data, 4);
01348                 case vertexAy:
01349                         if (chips & 1) v->fbi.ay = (INT16)(data&0xffff);
01350                         break;
01351 
01352                 case fvertexBx:
01353                         data = (UINT32)float_to_int32(data, 4);
01354                 case vertexBx:
01355                         if (chips & 1) v->fbi.bx = (INT16)(data&0xffff);
01356                         break;
01357 
01358                 case fvertexBy:
01359                         data = (UINT32)float_to_int32(data, 4);
01360                 case vertexBy:
01361                         if (chips & 1) v->fbi.by = (INT16)(data&0xffff);
01362                         break;
01363 
01364                 case fvertexCx:
01365                         data = (UINT32)float_to_int32(data, 4);
01366                 case vertexCx:
01367                         if (chips & 1) v->fbi.cx = (INT16)(data&0xffff);
01368                         break;
01369 
01370                 case fvertexCy:
01371                         data = (UINT32)float_to_int32(data, 4);
01372                 case vertexCy:
01373                         if (chips & 1) v->fbi.cy = (INT16)(data&0xffff);
01374                         break;
01375 
01376                 /* RGB data is 12.12 formatted fixed point */
01377                 case fstartR:
01378                         data = (UINT32)float_to_int32(data, 12);
01379                 case startR:
01380                         if (chips & 1) v->fbi.startr = (INT32)(data << 8) >> 8;
01381                         break;
01382 
01383                 case fstartG:
01384                         data = (UINT32)float_to_int32(data, 12);
01385                 case startG:
01386                         if (chips & 1) v->fbi.startg = (INT32)(data << 8) >> 8;
01387                         break;
01388 
01389                 case fstartB:
01390                         data = (UINT32)float_to_int32(data, 12);
01391                 case startB:
01392                         if (chips & 1) v->fbi.startb = (INT32)(data << 8) >> 8;
01393                         break;
01394 
01395                 case fstartA:
01396                         data = (UINT32)float_to_int32(data, 12);
01397                 case startA:
01398                         if (chips & 1) v->fbi.starta = (INT32)(data << 8) >> 8;
01399                         break;
01400 
01401                 case fdRdX:
01402                         data = (UINT32)float_to_int32(data, 12);
01403                 case dRdX:
01404                         if (chips & 1) v->fbi.drdx = (INT32)(data << 8) >> 8;
01405                         break;
01406 
01407                 case fdGdX:
01408                         data = (UINT32)float_to_int32(data, 12);
01409                 case dGdX:
01410                         if (chips & 1) v->fbi.dgdx = (INT32)(data << 8) >> 8;
01411                         break;
01412 
01413                 case fdBdX:
01414                         data = (UINT32)float_to_int32(data, 12);
01415                 case dBdX:
01416                         if (chips & 1) v->fbi.dbdx = (INT32)(data << 8) >> 8;
01417                         break;
01418 
01419                 case fdAdX:
01420                         data = (UINT32)float_to_int32(data, 12);
01421                 case dAdX:
01422                         if (chips & 1) v->fbi.dadx = (INT32)(data << 8) >> 8;
01423                         break;
01424 
01425                 case fdRdY:
01426                         data = (UINT32)float_to_int32(data, 12);
01427                 case dRdY:
01428                         if (chips & 1) v->fbi.drdy = (INT32)(data << 8) >> 8;
01429                         break;
01430 
01431                 case fdGdY:
01432                         data = (UINT32)float_to_int32(data, 12);
01433                 case dGdY:
01434                         if (chips & 1) v->fbi.dgdy = (INT32)(data << 8) >> 8;
01435                         break;
01436 
01437                 case fdBdY:
01438                         data = (UINT32)float_to_int32(data, 12);
01439                 case dBdY:
01440                         if (chips & 1) v->fbi.dbdy = (INT32)(data << 8) >> 8;
01441                         break;
01442 
01443                 case fdAdY:
01444                         data = (UINT32)float_to_int32(data, 12);
01445                 case dAdY:
01446                         if (chips & 1) v->fbi.dady = (INT32)(data << 8) >> 8;
01447                         break;
01448 
01449                 /* Z data is 20.12 formatted fixed point */
01450                 case fstartZ:
01451                         data = (UINT32)float_to_int32(data, 12);
01452                 case startZ:
01453                         if (chips & 1) v->fbi.startz = (INT32)data;
01454                         break;
01455 
01456                 case fdZdX:
01457                         data = (UINT32)float_to_int32(data, 12);
01458                 case dZdX:
01459                         if (chips & 1) v->fbi.dzdx = (INT32)data;
01460                         break;
01461 
01462                 case fdZdY:
01463                         data = (UINT32)float_to_int32(data, 12);
01464                 case dZdY:
01465                         if (chips & 1) v->fbi.dzdy = (INT32)data;
01466                         break;
01467 
01468                 /* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */
01469                 case fstartS:
01470                         data64 = float_to_int64(data, 32);
01471                         if (chips & 2) v->tmu[0].starts = data64;
01472                         if (chips & 4) v->tmu[1].starts = data64;
01473                         break;
01474                 case startS:
01475                         if (chips & 2) v->tmu[0].starts = (INT64)(INT32)data << 14;
01476                         if (chips & 4) v->tmu[1].starts = (INT64)(INT32)data << 14;
01477                         break;
01478 
01479                 case fstartT:
01480                         data64 = float_to_int64(data, 32);
01481                         if (chips & 2) v->tmu[0].startt = data64;
01482                         if (chips & 4) v->tmu[1].startt = data64;
01483                         break;
01484                 case startT:
01485                         if (chips & 2) v->tmu[0].startt = (INT64)(INT32)data << 14;
01486                         if (chips & 4) v->tmu[1].startt = (INT64)(INT32)data << 14;
01487                         break;
01488 
01489                 case fdSdX:
01490                         data64 = float_to_int64(data, 32);
01491                         if (chips & 2) v->tmu[0].dsdx = data64;
01492                         if (chips & 4) v->tmu[1].dsdx = data64;
01493                         break;
01494                 case dSdX:
01495                         if (chips & 2) v->tmu[0].dsdx = (INT64)(INT32)data << 14;
01496                         if (chips & 4) v->tmu[1].dsdx = (INT64)(INT32)data << 14;
01497                         break;
01498 
01499                 case fdTdX:
01500                         data64 = float_to_int64(data, 32);
01501                         if (chips & 2) v->tmu[0].dtdx = data64;
01502                         if (chips & 4) v->tmu[1].dtdx = data64;
01503                         break;
01504                 case dTdX:
01505                         if (chips & 2) v->tmu[0].dtdx = (INT64)(INT32)data << 14;
01506                         if (chips & 4) v->tmu[1].dtdx = (INT64)(INT32)data << 14;
01507                         break;
01508 
01509                 case fdSdY:
01510                         data64 = float_to_int64(data, 32);
01511                         if (chips & 2) v->tmu[0].dsdy = data64;
01512                         if (chips & 4) v->tmu[1].dsdy = data64;
01513                         break;
01514                 case dSdY:
01515                         if (chips & 2) v->tmu[0].dsdy = (INT64)(INT32)data << 14;
01516                         if (chips & 4) v->tmu[1].dsdy = (INT64)(INT32)data << 14;
01517                         break;
01518 
01519                 case fdTdY:
01520                         data64 = float_to_int64(data, 32);
01521                         if (chips & 2) v->tmu[0].dtdy = data64;
01522                         if (chips & 4) v->tmu[1].dtdy = data64;
01523                         break;
01524                 case dTdY:
01525                         if (chips & 2) v->tmu[0].dtdy = (INT64)(INT32)data << 14;
01526                         if (chips & 4) v->tmu[1].dtdy = (INT64)(INT32)data << 14;
01527                         break;
01528 
01529                 /* W data is 2.30 formatted fixed point, converted to 16.32 internally */
01530                 case fstartW:
01531                         data64 = float_to_int64(data, 32);
01532                         if (chips & 1) v->fbi.startw = data64;
01533                         if (chips & 2) v->tmu[0].startw = data64;
01534                         if (chips & 4) v->tmu[1].startw = data64;
01535                         break;
01536                 case startW:
01537                         if (chips & 1) v->fbi.startw = (INT64)(INT32)data << 2;
01538                         if (chips & 2) v->tmu[0].startw = (INT64)(INT32)data << 2;
01539                         if (chips & 4) v->tmu[1].startw = (INT64)(INT32)data << 2;
01540                         break;
01541 
01542                 case fdWdX:
01543                         data64 = float_to_int64(data, 32);
01544                         if (chips & 1) v->fbi.dwdx = data64;
01545                         if (chips & 2) v->tmu[0].dwdx = data64;
01546                         if (chips & 4) v->tmu[1].dwdx = data64;
01547                         break;
01548                 case dWdX:
01549                         if (chips & 1) v->fbi.dwdx = (INT64)(INT32)data << 2;
01550                         if (chips & 2) v->tmu[0].dwdx = (INT64)(INT32)data << 2;
01551                         if (chips & 4) v->tmu[1].dwdx = (INT64)(INT32)data << 2;
01552                         break;
01553 
01554                 case fdWdY:
01555                         data64 = float_to_int64(data, 32);
01556                         if (chips & 1) v->fbi.dwdy = data64;
01557                         if (chips & 2) v->tmu[0].dwdy = data64;
01558                         if (chips & 4) v->tmu[1].dwdy = data64;
01559                         break;
01560                 case dWdY:
01561                         if (chips & 1) v->fbi.dwdy = (INT64)(INT32)data << 2;
01562                         if (chips & 2) v->tmu[0].dwdy = (INT64)(INT32)data << 2;
01563                         if (chips & 4) v->tmu[1].dwdy = (INT64)(INT32)data << 2;
01564                         break;
01565 
01566                 /* setup bits */
01567                 case sARGB:
01568                         if (chips & 1)
01569                         {
01570                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01571                                 v->reg[sAlpha].f = (float)RGB_ALPHA(data);
01572                                 v->reg[sRed].f = (float)RGB_RED(data);
01573                                 v->reg[sGreen].f = (float)RGB_GREEN(data);
01574                                 v->reg[sBlue].f = (float)RGB_BLUE(data);
01575                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01576                         }
01577                         break;
01578 
01579                 /* mask off invalid bits for different cards */
01580                 case fbzColorPath:
01581                         if (v->type < VOODOO_2)
01582                                 data &= 0x0fffffff;
01583                         if (chips & 1) v->reg[fbzColorPath].u = data;
01584                         break;
01585 
01586                 case fbzMode:
01587                         if (v->type < VOODOO_2)
01588                                 data &= 0x001fffff;
01589                         if (chips & 1) {
01590                                 if (v->ogl && v->active && (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u)!=FBZMODE_Y_ORIGIN(data))) {
01591                                         v->reg[fbzMode].u = data;
01592                                         CPU_Core_Dyn_X86_SaveDHFPUState();
01593                                         voodoo_ogl_set_window(v);
01594                                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01595                                 } else {
01596                                         v->reg[fbzMode].u = data;
01597                                 }
01598                         }
01599                         break;
01600 
01601                 case fogMode:
01602                         if (v->type < VOODOO_2)
01603                                 data &= 0x0000003f;
01604                         if (chips & 1) v->reg[fogMode].u = data;
01605                         break;
01606 
01607                 /* triangle drawing */
01608                 case triangleCMD:
01609                         CPU_Core_Dyn_X86_SaveDHFPUState();
01610                         triangle(v);
01611                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01612                         break;
01613 
01614                 case ftriangleCMD:
01615                         CPU_Core_Dyn_X86_SaveDHFPUState();
01616                         triangle(v);
01617                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01618                         break;
01619 
01620                 case sBeginTriCMD:
01621 //                      E_Exit("begin tri");
01622                         CPU_Core_Dyn_X86_SaveDHFPUState();
01623                         begin_triangle(v);
01624                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01625                         break;
01626 
01627                 case sDrawTriCMD:
01628 //                      E_Exit("draw tri");
01629                         CPU_Core_Dyn_X86_SaveDHFPUState();
01630                         draw_triangle(v);
01631                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01632                         break;
01633 
01634                 /* other commands */
01635                 case nopCMD:
01636                         if (data & 1)
01637                                 reset_counters(v);
01638                         if (data & 2)
01639                                 v->reg[fbiTrianglesOut].u = 0;
01640                         break;
01641 
01642                 case fastfillCMD:
01643                         CPU_Core_Dyn_X86_SaveDHFPUState();
01644                         fastfill(v);
01645                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01646                         break;
01647 
01648                 case swapbufferCMD:
01649 //                      CPU_Core_Dyn_X86_SaveDHFPUState();
01650                         swapbuffer(v, data);
01651 //                      CPU_Core_Dyn_X86_RestoreDHFPUState();
01652                         break;
01653 
01654                 /* gamma table access -- Voodoo/Voodoo2 only */
01655                 case clutData:
01656 /*                      if (chips & 1)
01657                         {
01658                                 if (!FBIINIT1_VIDEO_TIMING_RESET(v->reg[fbiInit1].u))
01659                                 {
01660                                         int index = data >> 24;
01661                                         if (index <= 32)
01662                                         {
01663 //                                              v->fbi.clut[index] = data;
01664                                         }
01665                                 }
01666                                 else
01667                                         LOG(LOG_VOODOO,LOG_WARN)("clutData ignored because video timing reset = 1\n");
01668                         } */
01669                         break;
01670 
01671                 /* external DAC access -- Voodoo/Voodoo2 only */
01672                 case dacData:
01673                         if (chips & 1)
01674                         {
01675                                 if (!(data & 0x800))
01676                                         dacdata_w(&v->dac, (data >> 8) & 7, data & 0xff);
01677                                 else
01678                                         dacdata_r(&v->dac, (data >> 8) & 7);
01679                         }
01680                         break;
01681 
01682                 /* vertical sync rate -- Voodoo/Voodoo2 only */
01683                 case hSync:
01684                 case vSync:
01685                 case backPorch:
01686                 case videoDimensions:
01687                         if (chips & 1)
01688                         {
01689                                 v->reg[regnum].u = data;
01690                                 if (v->reg[hSync].u != 0 && v->reg[vSync].u != 0 && v->reg[videoDimensions].u != 0)
01691                                 {
01692                                         CPU_Core_Dyn_X86_SaveDHFPUState();
01693                                         int htotal = (int)(((v->reg[hSync].u >> 16) & 0x3ff) + 1u + (v->reg[hSync].u & 0xff) + 1u);
01694                                         int vtotal = (int)(((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff));
01695                                         int hvis = v->reg[videoDimensions].u & 0x3ff;
01696                                         int vvis = (v->reg[videoDimensions].u >> 16) & 0x3ff;
01697                                         int hbp = (int)((v->reg[backPorch].u & 0xff) + 2u);
01698                                         int vbp = (int)((v->reg[backPorch].u >> 16) & 0xff);
01699 //                                      attoseconds_t refresh = video_screen_get_frame_period(v->screen).attoseconds;
01700                                         attoseconds_t refresh = 0;
01701                                         attoseconds_t stdperiod, medperiod, vgaperiod;
01702                                         attoseconds_t stddiff, meddiff, vgadiff;
01703                                         rectangle visarea;
01704 
01705                                         /* create a new visarea */
01706                                         visarea.min_x = hbp;
01707                                         visarea.max_x = hbp + hvis - 1;
01708                                         visarea.min_y = vbp;
01709                                         visarea.max_y = vbp + vvis - 1;
01710 
01711                                         /* keep within bounds */
01712                                         visarea.max_x = MIN(visarea.max_x, htotal - 1);
01713                                         visarea.max_y = MIN(visarea.max_y, vtotal - 1);
01714 
01715                                         /* compute the new period for standard res, medium res, and VGA res */
01716                                         stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal;
01717                                         medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal;
01718                                         vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal;
01719 
01720                                         /* compute a diff against the current refresh period */
01721                                         stddiff = stdperiod - refresh;
01722                                         if (stddiff < 0) stddiff = -stddiff;
01723                                         meddiff = medperiod - refresh;
01724                                         if (meddiff < 0) meddiff = -meddiff;
01725                                         vgadiff = vgaperiod - refresh;
01726                                         if (vgadiff < 0) vgadiff = -vgadiff;
01727 
01728                                         LOG(LOG_VOODOO,LOG_WARN)("hSync=%08X  vSync=%08X  backPorch=%08X  videoDimensions=%08X\n",
01729                                                 v->reg[hSync].u, v->reg[vSync].u, v->reg[backPorch].u, v->reg[videoDimensions].u);
01730                                         LOG(LOG_VOODOO,LOG_WARN)("Horiz: %d-%d (%d total)  Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal);
01731 
01732                                         /* configure the screen based on which one matches the closest */
01733                                         if (stddiff < meddiff && stddiff < vgadiff)
01734                                         {
01735 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, stdperiod);
01736                                                 LOG(LOG_VOODOO,LOG_WARN)("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
01737                                         }
01738                                         else if (meddiff < vgadiff)
01739                                         {
01740 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, medperiod);
01741                                                 LOG(LOG_VOODOO,LOG_WARN)("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
01742                                         }
01743                                         else
01744                                         {
01745 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, vgaperiod);
01746                                                 LOG(LOG_VOODOO,LOG_WARN)("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod));
01747                                         }
01748 
01749                                         /* configure the new framebuffer info */
01750                                         UINT32 new_width = ((UINT32)hvis+1u) & ~1u;
01751                                         UINT32 new_height = ((UINT32)vvis+1u) & ~1u;
01752                                         if ((v->fbi.width != new_width) || (v->fbi.height != new_height)) {
01753                                                 v->fbi.width = new_width;
01754                                                 v->fbi.height = new_height;
01755                                                 v->ogl_dimchange = true;
01756                                         }
01757 //                                      v->fbi.xoffs = hbp;
01758 //                                      v->fbi.yoffs = vbp;
01759 //                                      v->fbi.vsyncscan = (v->reg[vSync].u >> 16) & 0xfff;
01760 
01761                                         /* recompute the time of VBLANK */
01762 //                                      adjust_vblank_timer(v);
01763 
01764                                         /* if changing dimensions, update video memory layout */
01765                                         if (regnum == videoDimensions)
01766                                                 recompute_video_memory(v);
01767 
01768                                         Voodoo_UpdateScreenStart();
01769                                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01770                                 }
01771                         }
01772                         break;
01773 
01774                 /* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
01775                 case fbiInit0:
01776                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01777                         {
01778                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01779                                 Voodoo_Output_Enable(FBIINIT0_VGA_PASSTHRU(data));
01780                                 v->reg[fbiInit0].u = data;
01781                                 if (FBIINIT0_GRAPHICS_RESET(data))
01782                                         soft_reset(v);
01783                                 recompute_video_memory(v);
01784                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01785                         }
01786                         break;
01787 
01788                 /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */
01789                 case fbiInit5:
01790                 case fbiInit6:
01791                         if (v->type < VOODOO_2)
01792                                 break;
01793                         /* else fall through... */
01794 
01795                 /* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
01796                 /* most of these affect memory layout, so always recompute that when done */
01797                 case fbiInit1:
01798                 case fbiInit2:
01799                 case fbiInit4:
01800                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01801                         {
01802                                 v->reg[regnum].u = data;
01803                                 recompute_video_memory(v);
01804                         }
01805                         break;
01806 
01807                 case fbiInit3:
01808                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01809                         {
01810                                 v->reg[regnum].u = data;
01811                                 v->alt_regmap = (FBIINIT3_TRI_REGISTER_REMAP(data) > 0);
01812                                 v->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(v->reg[fbiInit3].u);
01813                                 recompute_video_memory(v);
01814                         }
01815                         break;
01816 
01817                 /* nccTable entries are processed and expanded immediately */
01818                 case nccTable+0:
01819                 case nccTable+1:
01820                 case nccTable+2:
01821                 case nccTable+3:
01822                 case nccTable+4:
01823                 case nccTable+5:
01824                 case nccTable+6:
01825                 case nccTable+7:
01826                 case nccTable+8:
01827                 case nccTable+9:
01828                 case nccTable+10:
01829                 case nccTable+11:
01830                         if (chips & 2) ncc_table_write(&v->tmu[0].ncc[0], regnum - nccTable, data);
01831                         if (chips & 4) ncc_table_write(&v->tmu[1].ncc[0], regnum - nccTable, data);
01832                         break;
01833 
01834                 case nccTable+12:
01835                 case nccTable+13:
01836                 case nccTable+14:
01837                 case nccTable+15:
01838                 case nccTable+16:
01839                 case nccTable+17:
01840                 case nccTable+18:
01841                 case nccTable+19:
01842                 case nccTable+20:
01843                 case nccTable+21:
01844                 case nccTable+22:
01845                 case nccTable+23:
01846                         if (chips & 2) ncc_table_write(&v->tmu[0].ncc[1], regnum - (nccTable+12), data);
01847                         if (chips & 4) ncc_table_write(&v->tmu[1].ncc[1], regnum - (nccTable+12), data);
01848                         break;
01849 
01850                 /* fogTable entries are processed and expanded immediately */
01851                 case fogTable+0:
01852                 case fogTable+1:
01853                 case fogTable+2:
01854                 case fogTable+3:
01855                 case fogTable+4:
01856                 case fogTable+5:
01857                 case fogTable+6:
01858                 case fogTable+7:
01859                 case fogTable+8:
01860                 case fogTable+9:
01861                 case fogTable+10:
01862                 case fogTable+11:
01863                 case fogTable+12:
01864                 case fogTable+13:
01865                 case fogTable+14:
01866                 case fogTable+15:
01867                 case fogTable+16:
01868                 case fogTable+17:
01869                 case fogTable+18:
01870                 case fogTable+19:
01871                 case fogTable+20:
01872                 case fogTable+21:
01873                 case fogTable+22:
01874                 case fogTable+23:
01875                 case fogTable+24:
01876                 case fogTable+25:
01877                 case fogTable+26:
01878                 case fogTable+27:
01879                 case fogTable+28:
01880                 case fogTable+29:
01881                 case fogTable+30:
01882                 case fogTable+31:
01883                         if (chips & 1)
01884                         {
01885                                 int base = 2 * (int)(regnum - fogTable);
01886                                 v->fbi.fogdelta[base + 0] = (data >> 0) & 0xff;
01887                                 v->fbi.fogblend[base + 0] = (data >> 8) & 0xff;
01888                                 v->fbi.fogdelta[base + 1] = (data >> 16) & 0xff;
01889                                 v->fbi.fogblend[base + 1] = (data >> 24) & 0xff;
01890                         }
01891                         break;
01892 
01893                 /* texture modifications cause us to recompute everything */
01894                 case textureMode:
01895                 case tLOD:
01896                 case tDetail:
01897                 case texBaseAddr:
01898                 case texBaseAddr_1:
01899                 case texBaseAddr_2:
01900                 case texBaseAddr_3_8:
01901                         if (chips & 2)
01902                         {
01903                                 v->tmu[0].reg[regnum].u = data;
01904                                 v->tmu[0].regdirty = true;
01905                         }
01906                         if (chips & 4)
01907                         {
01908                                 v->tmu[1].reg[regnum].u = data;
01909                                 v->tmu[1].regdirty = true;
01910                         }
01911                         break;
01912 
01913                 case trexInit1:
01914                         /* send tmu config data to the frame buffer */
01915                         v->send_config = (TREXINIT_SEND_TMU_CONFIG(data) > 0);
01916                         goto default_case;
01917                         break;
01918 
01919                 case clipLowYHighY:
01920                 case clipLeftRight:
01921                         if (chips & 1) v->reg[0x000 + regnum].u = data;
01922                         if (v->ogl) {
01923                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01924                                 voodoo_ogl_clip_window(v);
01925                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01926                         }
01927                         break;
01928 
01929                 /* these registers are referenced in the renderer; we must wait for pending work before changing */
01930                 case chromaRange:
01931                 case chromaKey:
01932                 case alphaMode:
01933                 case fogColor:
01934                 case stipple:
01935                 case zaColor:
01936                 case color1:
01937                 case color0:
01938                         /* fall through to default implementation */
01939 
01940                 /* by default, just feed the data to the chips */
01941                 default:
01942 default_case:
01943                         if (chips & 1) v->reg[0x000 + regnum].u = data;
01944                         if (chips & 2) v->reg[0x100 + regnum].u = data;
01945                         if (chips & 4) v->reg[0x200 + regnum].u = data;
01946                         if (chips & 8) v->reg[0x300 + regnum].u = data;
01947                         break;
01948         }
01949 
01950 }
01951 
01952 
01953 
01954 /*************************************
01955  *
01956  *  Voodoo LFB writes
01957  *
01958  *************************************/
01959 
01960 void lfb_w(UINT32 offset, UINT32 data, UINT32 mem_mask) {
01961         LOG(LOG_VOODOO,LOG_WARN)("V3D:WR LFB offset %X value %08X", offset, data);
01962         UINT16 *dest, *depth;
01963         UINT32 destmax, depthmax;
01964 
01965         int sr[2], sg[2], sb[2], sa[2], sw[2];
01966         int x, y, scry, mask;
01967         int pix, destbuf;
01968 
01969         /* byte swizzling */
01970         if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u))
01971         {
01972                 data = FLIPENDIAN_INT32(data);
01973                 mem_mask = FLIPENDIAN_INT32(mem_mask);
01974         }
01975 
01976         /* word swapping */
01977         if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u))
01978         {
01979                 data = (data << 16) | (data >> 16);
01980                 mem_mask = (mem_mask << 16) | (mem_mask >> 16);
01981         }
01982 
01983         /* extract default depth and alpha values */
01984         sw[0] = sw[1] = (int)(v->reg[zaColor].u & 0xffff);
01985         sa[0] = sa[1] = (int)(v->reg[zaColor].u >> 24);
01986 
01987         /* first extract A,R,G,B from the data */
01988         switch (LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(v->reg[lfbMode].u))
01989         {
01990                 case 16*0 + 0:          /* ARGB, 16-bit RGB 5-6-5 */
01991                 case 16*2 + 0:          /* RGBA, 16-bit RGB 5-6-5 */
01992                         EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
01993                         EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]);
01994                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
01995                         offset <<= 1;
01996                         break;
01997                 case 16*1 + 0:          /* ABGR, 16-bit RGB 5-6-5 */
01998                 case 16*3 + 0:          /* BGRA, 16-bit RGB 5-6-5 */
01999                         EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
02000                         EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02001                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02002                         offset <<= 1;
02003                         break;
02004 
02005                 case 16*0 + 1:          /* ARGB, 16-bit RGB x-5-5-5 */
02006                         EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
02007                         EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]);
02008                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02009                         offset <<= 1;
02010                         break;
02011                 case 16*1 + 1:          /* ABGR, 16-bit RGB x-5-5-5 */
02012                         EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
02013                         EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02014                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02015                         offset <<= 1;
02016                         break;
02017                 case 16*2 + 1:          /* RGBA, 16-bit RGB x-5-5-5 */
02018                         EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
02019                         EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]);
02020                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02021                         offset <<= 1;
02022                         break;
02023                 case 16*3 + 1:          /* BGRA, 16-bit RGB x-5-5-5 */
02024                         EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
02025                         EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02026                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02027                         offset <<= 1;
02028                         break;
02029 
02030                 case 16*0 + 2:          /* ARGB, 16-bit ARGB 1-5-5-5 */
02031                         EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02032                         EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]);
02033                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02034                         offset <<= 1;
02035                         break;
02036                 case 16*1 + 2:          /* ABGR, 16-bit ARGB 1-5-5-5 */
02037                         EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02038                         EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]);
02039                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02040                         offset <<= 1;
02041                         break;
02042                 case 16*2 + 2:          /* RGBA, 16-bit ARGB 1-5-5-5 */
02043                         EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02044                         EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]);
02045                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02046                         offset <<= 1;
02047                         break;
02048                 case 16*3 + 2:          /* BGRA, 16-bit ARGB 1-5-5-5 */
02049                         EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02050                         EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]);
02051                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02052                         offset <<= 1;
02053                         break;
02054 
02055                 case 16*0 + 4:          /* ARGB, 32-bit RGB x-8-8-8 */
02056                         EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]);
02057                         mask = LFB_RGB_PRESENT;
02058                         break;
02059                 case 16*1 + 4:          /* ABGR, 32-bit RGB x-8-8-8 */
02060                         EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]);
02061                         mask = LFB_RGB_PRESENT;
02062                         break;
02063                 case 16*2 + 4:          /* RGBA, 32-bit RGB x-8-8-8 */
02064                         EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]);
02065                         mask = LFB_RGB_PRESENT;
02066                         break;
02067                 case 16*3 + 4:          /* BGRA, 32-bit RGB x-8-8-8 */
02068                         EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]);
02069                         mask = LFB_RGB_PRESENT;
02070                         break;
02071 
02072                 case 16*0 + 5:          /* ARGB, 32-bit ARGB 8-8-8-8 */
02073                         EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02074                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02075                         break;
02076                 case 16*1 + 5:          /* ABGR, 32-bit ARGB 8-8-8-8 */
02077                         EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02078                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02079                         break;
02080                 case 16*2 + 5:          /* RGBA, 32-bit ARGB 8-8-8-8 */
02081                         EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02082                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02083                         break;
02084                 case 16*3 + 5:          /* BGRA, 32-bit ARGB 8-8-8-8 */
02085                         EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02086                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02087                         break;
02088 
02089                 case 16*0 + 12:         /* ARGB, 32-bit depth+RGB 5-6-5 */
02090                 case 16*2 + 12:         /* RGBA, 32-bit depth+RGB 5-6-5 */
02091                         sw[0] = (int)(data >> 16);
02092                         EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
02093                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02094                         break;
02095                 case 16*1 + 12:         /* ABGR, 32-bit depth+RGB 5-6-5 */
02096                 case 16*3 + 12:         /* BGRA, 32-bit depth+RGB 5-6-5 */
02097                         sw[0] = (int)(data >> 16);
02098                         EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
02099                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02100                         break;
02101 
02102                 case 16*0 + 13:         /* ARGB, 32-bit depth+RGB x-5-5-5 */
02103                         sw[0] = (int)(data >> 16);
02104                         EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
02105                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02106                         break;
02107                 case 16*1 + 13:         /* ABGR, 32-bit depth+RGB x-5-5-5 */
02108                         sw[0] = (int)(data >> 16);
02109                         EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
02110                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02111                         break;
02112                 case 16*2 + 13:         /* RGBA, 32-bit depth+RGB x-5-5-5 */
02113                         sw[0] = (int)(data >> 16);
02114                         EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
02115                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02116                         break;
02117                 case 16*3 + 13:         /* BGRA, 32-bit depth+RGB x-5-5-5 */
02118                         sw[0] = (int)(data >> 16);
02119                         EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
02120                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02121                         break;
02122 
02123                 case 16*0 + 14:         /* ARGB, 32-bit depth+ARGB 1-5-5-5 */
02124                         sw[0] = (int)(data >> 16);
02125                         EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02126                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02127                         break;
02128                 case 16*1 + 14:         /* ABGR, 32-bit depth+ARGB 1-5-5-5 */
02129                         sw[0] = (int)(data >> 16);
02130                         EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02131                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02132                         break;
02133                 case 16*2 + 14:         /* RGBA, 32-bit depth+ARGB 1-5-5-5 */
02134                         sw[0] = (int)(data >> 16);
02135                         EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02136                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02137                         break;
02138                 case 16*3 + 14:         /* BGRA, 32-bit depth+ARGB 1-5-5-5 */
02139                         sw[0] = (int)(data >> 16);
02140                         EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02141                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02142                         break;
02143 
02144                 case 16*0 + 15:         /* ARGB, 16-bit depth */
02145                 case 16*1 + 15:         /* ARGB, 16-bit depth */
02146                 case 16*2 + 15:         /* ARGB, 16-bit depth */
02147                 case 16*3 + 15:         /* ARGB, 16-bit depth */
02148                         sw[0] = (int)(data & 0xffff);
02149                         sw[1] = (int)(data >> 16);
02150                         mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4);
02151                         offset <<= 1;
02152                         break;
02153 
02154                 default:                        /* reserved */
02155                         return;
02156         }
02157 
02158         /* compute X,Y */
02159         x = (offset << 0) & ((1 << 10) - 1);
02160         y = (offset >> 10) & ((1 << 10) - 1);
02161 
02162         /* adjust the mask based on which half of the data is written */
02163         if (!ACCESSING_BITS_0_15)
02164                 mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW);
02165         if (!ACCESSING_BITS_16_31)
02166                 mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW);
02167 
02168         /* select the target buffer */
02169         destbuf = LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u);
02170 //      LOG(LOG_VOODOO,LOG_WARN)("destbuf %X lfbmode %X",destbuf, v->reg[lfbMode].u);
02171         switch (destbuf)
02172         {
02173                 case 0:                 /* front buffer */
02174                         dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
02175                         destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
02176                         break;
02177 
02178                 case 1:                 /* back buffer */
02179                         dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
02180                         destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
02181                         break;
02182 
02183                 default:                /* reserved */
02184                         E_Exit("reserved lfb write");
02185                         return;
02186         }
02187         depth = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
02188         depthmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
02189 
02190         /* simple case: no pipeline */
02191         if (!LFBMODE_ENABLE_PIXEL_PIPELINE(v->reg[lfbMode].u))
02192         {
02193                 DECLARE_DITHER_POINTERS_NO_DITHER_VAR;
02194                 UINT32 bufoffs;
02195 
02196                 if (LOG_LFB) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
02197 
02198                 /* determine the screen Y */
02199                 scry = y;
02200                 if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
02201                         scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02202 
02203                 /* advance pointers to the proper row */
02204                 bufoffs = (unsigned long)((long)scry * (long)v->fbi.rowpixels + (long)x);
02205 
02206                 /* compute dithering */
02207                 COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y);
02208 
02209                 /* loop over up to two pixels */
02210                 for (pix = 0; mask; pix++)
02211                 {
02212                         /* make sure we care about this pixel */
02213                         if (mask & 0x0f)
02214                         {
02215                                 bool has_rgb = (mask & LFB_RGB_PRESENT) > 0;
02216                                 bool has_alpha = ((mask & LFB_ALPHA_PRESENT) > 0) && (FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u) > 0);
02217                                 bool has_depth = ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u));
02218                                 if (v->ogl && v->active) {
02219                                         if (has_rgb || has_alpha) {
02220                                                 // if enabling dithering: output is 565 not 888 anymore
02221 //                                              APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
02222                                                 voodoo_ogl_draw_pixel(x, scry, has_rgb, has_alpha, sr[pix], sg[pix], sb[pix], sa[pix]);
02223                                         }
02224                                         if (has_depth) {
02225 #if C_OPENGL
02226                                                 voodoo_ogl_draw_z(x, scry+1, sw[pix]);
02227 #endif
02228                                         }
02229                                 } else {
02230                                         /* write to the RGB buffer */
02231                                         if (has_rgb && bufoffs < destmax)
02232                                         {
02233                                                 /* apply dithering and write to the screen */
02234                                                 APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
02235                                                 dest[bufoffs] = (UINT16)((sr[pix] << 11) | (sg[pix] << 5) | sb[pix]);
02236                                         }
02237 
02238                                         /* make sure we have an aux buffer to write to */
02239                                         if (depth && bufoffs < depthmax)
02240                                         {
02241                                                 /* write to the alpha buffer */
02242                                                 if (has_alpha)
02243                                                         depth[bufoffs] = (UINT16)sa[pix];
02244 
02245                                                 /* write to the depth buffer */
02246                                                 if (has_depth)
02247                                                         depth[bufoffs] = (UINT16)sw[pix];
02248                                         }
02249                                 }
02250 
02251                                 /* track pixel writes to the frame buffer regardless of mask */
02252                                 v->reg[fbiPixelsOut].u++;
02253                         }
02254 
02255                         /* advance our pointers */
02256                         bufoffs++;
02257                         x++;
02258                         mask >>= 4;
02259                 }
02260         }
02261 
02262         /* tricky case: run the full pixel pipeline on the pixel */
02263         else
02264         {
02265                 DECLARE_DITHER_POINTERS;
02266 
02267                 if (LOG_LFB) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask);
02268 
02269                 /* determine the screen Y */
02270                 scry = y;
02271                 if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
02272                         scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02273 
02274                 /* advance pointers to the proper row */
02275                 dest += (unsigned long)((long)scry * (long)v->fbi.rowpixels);
02276                 if (depth)
02277                         depth += (unsigned long)((long)scry * (long)v->fbi.rowpixels);
02278 
02279                 /* compute dithering */
02280                 COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
02281 
02282                 /* loop over up to two pixels */
02283                 for (pix = 0; mask; pix++)
02284                 {
02285                         /* make sure we care about this pixel */
02286                         if (mask & 0x0f)
02287                         {
02288                                 stats_block *stats = &v->fbi.lfb_stats;
02289                                 INT64 iterw;
02290                                 if (LFBMODE_WRITE_W_SELECT(v->reg[lfbMode].u)) {
02291                                         iterw = (UINT32) v->reg[zaColor].u << 16;
02292                                 } else {
02293                                         iterw = (UINT32) sw[pix] << 16;
02294                                 }
02295                                 INT32 iterz = sw[pix] << 12;
02296                                 rgb_union color;
02297                                 rgb_union iterargb = { 0 };
02298 
02299                                 /* apply clipping */
02300                                 if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u))
02301                                 {
02302                                         if (x < (INT32)((v->reg[clipLeftRight].u >> 16) & 0x3ff) ||
02303                                                 x >= (INT32)(v->reg[clipLeftRight].u & 0x3ff) ||
02304                                                 scry < (INT32)((v->reg[clipLowYHighY].u >> 16) & 0x3ff) ||
02305                                                 scry >= (INT32)(v->reg[clipLowYHighY].u & 0x3ff))
02306                                         {
02307                                                 stats->pixels_in++;
02308                                                 stats->clip_fail++;
02309                                                 goto nextpixel;
02310                                         }
02311                                 }
02312 
02313                                 /* pixel pipeline part 1 handles depth testing and stippling */
02314                                 // TODO: in the v->ogl case this macro doesn't really work with depth testing
02315                                 // PIXEL_PIPELINE_BEGIN(v, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw);
02316 // Start PIXEL_PIPE_BEGIN copy
02317                                         INT32 fogdepth, biasdepth;
02318                                         INT32 prefogr, prefogg, prefogb;
02319                                         INT32 r, g, b, a;
02320 
02321                                         (stats)->pixels_in++;
02322 
02323                                         /* apply clipping */
02324                                         /* note that for perf reasons, we assume the caller has done clipping */
02325 
02326                                         /* handle stippling */
02327                                         if (FBZMODE_ENABLE_STIPPLE(v->reg[fbzMode].u))
02328                                         {
02329                                                 /* rotate mode */
02330                                                 if (FBZMODE_STIPPLE_PATTERN(v->reg[fbzMode].u) == 0)
02331                                                 {
02332                                                         v->reg[stipple].u = (v->reg[stipple].u << 1) | (v->reg[stipple].u >> 31);
02333                                                         if ((v->reg[stipple].u & 0x80000000) == 0)
02334                                                         {
02335                                                                 goto skipdrawdepth;
02336                                                         }
02337                                                 }
02338 
02339                                                 /* pattern mode */
02340                                                 else
02341                                                 {
02342                                                         int stipple_index = ((y & 3) << 3) | (~x & 7);
02343                                                         if (((v->reg[stipple].u >> stipple_index) & 1) == 0)
02344                                                         {
02345                                                                 goto nextpixel;
02346                                                         }
02347                                                 }
02348                                         }
02349 // End PIXEL_PIPELINE_BEGIN COPY
02350 
02351                                 // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used
02352                                 fogdepth = biasdepth = (INT32) sw[pix];
02353 
02354                                 color.rgb.r = sr[pix];
02355                                 color.rgb.g = sg[pix];
02356                                 color.rgb.b = sb[pix];
02357                                 color.rgb.a = sa[pix];
02358 
02359                                 /* Perform depth testing */
02360                                 DEPTH_TEST(v, stats, x, v->reg[fbzMode].u);     
02361 
02362                                 /* apply chroma key */
02363                                 APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, color);
02364 
02365                                 /* apply alpha mask, and alpha testing */
02366                                 APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, color.rgb.a);
02367                                 APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, color.rgb.a);
02368 
02369 
02370                                 if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp mselect %8x",FBZCP_CC_MSELECT(v->reg[fbzColorPath].u));
02371                                 if (FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u) > 1) LOG_MSG("lfbw fpp mselect alpha %8x",FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u));
02372 
02373                                 if (FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u) != 0) {
02374                                         if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp rblend %8x",FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u));
02375                                 }
02376                                 if (FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u) != 0) {
02377                                         if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp rblend alpha %8x",FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u));
02378                                 }
02379 
02380 
02381                                 INT32 blendr, blendg, blendb, blenda;
02382                                 rgb_union c_local;
02383 
02384                                 /* compute c_local */
02385                                 if (FBZCP_CC_LOCALSELECT_OVERRIDE(v->reg[fbzColorPath].u) == 0)
02386                                 {
02387                                         if (FBZCP_CC_LOCALSELECT(v->reg[fbzColorPath].u) == 0)  /* iterated RGB */
02388                                         {
02389 //                                              c_local.u = iterargb.u;
02390                                                 c_local.rgb.r = sr[pix];
02391                                                 c_local.rgb.g = sg[pix];
02392                                                 c_local.rgb.b = sb[pix];
02393                                         }
02394                                         else                                                                                    /* color0 RGB */
02395                                                 c_local.u = v->reg[color0].u;
02396                                 }
02397                                 else
02398                                 {
02399                                         LOG_MSG("lfbw fpp FBZCP_CC_LOCALSELECT_OVERRIDE set!");
02400 /*                                      if (!(texel.rgb.a & 0x80))                                      // iterated RGB
02401                                                 c_local.u = iterargb.u;
02402                                         else                                                                                    // color0 RGB
02403                                                 c_local.u = v->reg[color0].u; */
02404                                 }
02405 
02406                                 /* compute a_local */
02407                                 switch (FBZCP_CCA_LOCALSELECT(v->reg[fbzColorPath].u))
02408                                 {
02409                                         default:
02410                                         case 0:         /* iterated alpha */
02411 //                                              c_local.rgb.a = iterargb.rgb.a;
02412                                                 c_local.rgb.a = sa[pix];
02413                                                 break;
02414                                         case 1:         /* color0 alpha */
02415                                                 c_local.rgb.a = v->reg[color0].rgb.a;
02416                                                 break;
02417                                         case 2:         /* clamped iterated Z[27:20] */
02418                                         {
02419                                                 int temp;
02420                                                 CLAMPED_Z(iterz, v->reg[fbzColorPath].u, temp);
02421                                                 c_local.rgb.a = (UINT8)temp;
02422                                                 break;
02423                                         }
02424                                         case 3:         /* clamped iterated W[39:32] */
02425                                         {
02426                                                 int temp;
02427                                                 CLAMPED_W(iterw, v->reg[fbzColorPath].u, temp);                 /* Voodoo 2 only */
02428                                                 c_local.rgb.a = (UINT8)temp;
02429                                                 break;
02430                                         }
02431                                 }
02432 
02433                                 /* select zero or c_other */
02434                                 if (FBZCP_CC_ZERO_OTHER(v->reg[fbzColorPath].u) == 0) {
02435                                         r = sr[pix];
02436                                         g = sg[pix];
02437                                         b = sb[pix];
02438                                 } else {
02439                                         r = g = b = 0;
02440                                 }
02441 
02442                                 /* select zero or a_other */
02443                                 if (FBZCP_CCA_ZERO_OTHER(v->reg[fbzColorPath].u) == 0) {
02444                                         a = sa[pix];
02445                                 } else {
02446                                         a = 0;
02447                                 }
02448 
02449                                 /* subtract c_local */
02450                                 if (FBZCP_CC_SUB_CLOCAL(v->reg[fbzColorPath].u))
02451                                 {
02452                                         r -= c_local.rgb.r;
02453                                         g -= c_local.rgb.g;
02454                                         b -= c_local.rgb.b;
02455                                 }
02456 
02457                                 /* subtract a_local */
02458                                 if (FBZCP_CCA_SUB_CLOCAL(v->reg[fbzColorPath].u))
02459                                         a -= c_local.rgb.a;
02460 
02461                                 /* blend RGB */
02462                                 switch (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u))
02463                                 {
02464                                         default:        /* reserved */
02465                                         case 0:         /* 0 */
02466                                                 blendr = blendg = blendb = 0;
02467                                                 break;
02468                                         case 1:         /* c_local */
02469                                                 blendr = c_local.rgb.r;
02470                                                 blendg = c_local.rgb.g;
02471                                                 blendb = c_local.rgb.b;
02472                                                 LOG_MSG("blend RGB c_local");
02473                                                 break;
02474                                         case 2:         /* a_other */
02475                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02476 //                                              blendr = blendg = blendb = c_other.rgb.a;
02477                                                 LOG_MSG("blend RGB a_other");
02478                                                 break;
02479                                         case 3:         /* a_local */
02480                                                 blendr = blendg = blendb = c_local.rgb.a;
02481                                                 LOG_MSG("blend RGB a_local");
02482                                                 break;
02483                                         case 4:         /* texture alpha */
02484                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02485 //                                              blendr = blendg = blendb = texel.rgb.a;
02486                                                 LOG_MSG("blend RGB texture alpha");
02487                                                 break;
02488                                         case 5:         /* texture RGB (Voodoo 2 only) */
02489                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02490 /*                                              blendr = texel.rgb.r;
02491                                                 blendg = texel.rgb.g;
02492                                                 blendb = texel.rgb.b; */
02493                                                 LOG_MSG("blend RGB texture RGB");
02494                                                 break;
02495                                 }
02496 
02497                                 /* blend alpha */
02498                                 switch (FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u))
02499                                 {
02500                                         default:        /* reserved */
02501                                         case 0:         /* 0 */
02502                                                 blenda = 0;
02503                                                 break;
02504                                         case 1:         /* a_local */
02505                                                 blenda = c_local.rgb.a;
02506 //                                              LOG_MSG("blend alpha a_local");
02507                                                 break;
02508                                         case 2:         /* a_other */
02509                                                 blenda = 0; /* HACK: gotta fill it with something */
02510 //                                              blenda = c_other.rgb.a;
02511                                                 LOG_MSG("blend alpha a_other");
02512                                                 break;
02513                                         case 3:         /* a_local */
02514                                                 blenda = c_local.rgb.a;
02515                                                 LOG_MSG("blend alpha a_local");
02516                                                 break;
02517                                         case 4:         /* texture alpha */
02518                                                 blenda = 0; /* HACK: gotta fill it with something */
02519 //                                              blenda = texel.rgb.a;
02520                                                 LOG_MSG("blend alpha texture alpha");
02521                                                 break;
02522                                 }
02523 
02524                                 /* reverse the RGB blend */
02525                                 if (!FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u))
02526                                 {
02527                                         blendr ^= 0xff;
02528                                         blendg ^= 0xff;
02529                                         blendb ^= 0xff;
02530                                 }
02531 
02532                                 /* reverse the alpha blend */
02533                                 if (!FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u))
02534                                         blenda ^= 0xff;
02535 
02536                                 /* do the blend */
02537                                 r = (r * (blendr + 1)) >> 8;
02538                                 g = (g * (blendg + 1)) >> 8;
02539                                 b = (b * (blendb + 1)) >> 8;
02540                                 a = (a * (blenda + 1)) >> 8;
02541 
02542                                 /* add clocal or alocal to RGB */
02543                                 switch (FBZCP_CC_ADD_ACLOCAL(v->reg[fbzColorPath].u))
02544                                 {
02545                                         case 3:         /* reserved */
02546                                         case 0:         /* nothing */
02547                                                 break;
02548                                         case 1:         /* add c_local */
02549                                                 r += c_local.rgb.r;
02550                                                 g += c_local.rgb.g;
02551                                                 b += c_local.rgb.b;
02552                                                 break;
02553                                         case 2:         /* add_alocal */
02554                                                 r += c_local.rgb.a;
02555                                                 g += c_local.rgb.a;
02556                                                 b += c_local.rgb.a;
02557                                                 break;
02558                                 }
02559 
02560                                 /* add clocal or alocal to alpha */
02561                                 if (FBZCP_CCA_ADD_ACLOCAL(v->reg[fbzColorPath].u))
02562                                         a += c_local.rgb.a;
02563 
02564                                 /* clamp */
02565                                 CLAMP(r, 0x00, 0xff);
02566                                 CLAMP(g, 0x00, 0xff);
02567                                 CLAMP(b, 0x00, 0xff);
02568                                 CLAMP(a, 0x00, 0xff);
02569 
02570                                 /* invert */
02571                                 if (FBZCP_CC_INVERT_OUTPUT(v->reg[fbzColorPath].u))
02572                                 {
02573                                         r ^= 0xff;
02574                                         g ^= 0xff;
02575                                         b ^= 0xff;
02576                                 }
02577                                 if (FBZCP_CCA_INVERT_OUTPUT(v->reg[fbzColorPath].u))
02578                                         a ^= 0xff;
02579 
02580                                 if (v->ogl && v->active) {
02581                                         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u)) {
02582 //                                              APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b);
02583                                                 voodoo_ogl_draw_pixel_pipeline(x, scry, r, g, b);
02584                                         }
02585 /*                                      if (depth && FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u)) {
02586                                                 if (FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u) == 0)
02587                                                         voodoo_ogl_draw_z(x, y, depthval&0xffff, depthval>>16);
02588 //                                              else
02589 //                                                      depth[XX] = a;
02590                                         } */
02591                                 } else {
02592                                         /* pixel pipeline part 2 handles color combine, fog, alpha, and final output */
02593                                         PIXEL_PIPELINE_MODIFY(v, dither, dither4, x, v->reg[fbzMode].u, v->reg[fbzColorPath].u, v->reg[alphaMode].u, v->reg[fogMode].u, iterz, iterw, iterargb);
02594 
02595                                         PIXEL_PIPELINE_FINISH(v, dither_lookup, x, dest, depth, v->reg[fbzMode].u);
02596                                 }
02597 
02598                                 PIXEL_PIPELINE_END(stats);
02599 nextpixel:
02600                         /* advance our pointers */
02601                         x++;
02602                         mask >>= 4;
02603                 }
02604         }
02605 }
02606 
02607 
02608 
02609 /*************************************
02610  *
02611  *  Voodoo texture RAM writes
02612  *
02613  *************************************/
02614 
02615 INT32 texture_w(UINT32 offset, UINT32 data) {
02616         int tmunum = (offset >> 19) & 0x03;
02617         LOG(LOG_VOODOO,LOG_WARN)("V3D:write TMU%x offset %X value %X", tmunum, offset, data);
02618 
02619         tmu_state *t;
02620 
02621         /* point to the right TMU */
02622         if (!(v->chipmask & (2 << tmunum)))
02623                 return 0;
02624         t = &v->tmu[tmunum];
02625 
02626         if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u))
02627                 E_Exit("Texture direct write!");
02628 
02629         /* update texture info if dirty */
02630         if (t->regdirty)
02631                 recompute_texture_params(t);
02632 
02633         /* swizzle the data */
02634         if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u))
02635                 data = FLIPENDIAN_INT32(data);
02636         if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u))
02637                 data = (data >> 16) | (data << 16);
02638 
02639         /* 8-bit texture case */
02640         if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8)
02641         {
02642                 int lod, tt, ts;
02643                 UINT32 tbaseaddr;
02644                 UINT8 *dest;
02645 
02646                 /* extract info */
02647                 lod = (offset >> 15) & 0x0f;
02648                 tt = (offset >> 7) & 0xff;
02649 
02650                 /* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */
02651                 if (TEXMODE_SEQ_8_DOWNLD(v->tmu[0].reg/*t->reg*/[textureMode].u))
02652                         ts = (offset << 2) & 0xfc;
02653                 else
02654                         ts = (offset << 1) & 0xfc;
02655 
02656                 /* validate parameters */
02657                 if (lod > 8)
02658                         return 0;
02659 
02660                 /* compute the base address */
02661                 tbaseaddr = t->lodoffset[lod];
02662                 tbaseaddr += (UINT32)((long)tt * (((long)t->wmask >> lod) + 1l) + (long)ts);
02663 
02664                 if (LOG_TEXTURE_RAM) LOG(LOG_VOODOO,LOG_WARN)("Texture 8-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
02665 
02666                 /* write the four bytes in little-endian order */
02667                 dest = t->ram;
02668                 tbaseaddr &= t->mask;
02669 
02670                 bool changed = false;
02671                 if (dest[BYTE4_XOR_LE(tbaseaddr + 0)] != ((data >> 0) & 0xff)) {
02672                         dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff;
02673                         changed = true;
02674                 }
02675                 if (dest[BYTE4_XOR_LE(tbaseaddr + 1)] != ((data >> 8) & 0xff)) {
02676                         dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff;
02677                         changed = true;
02678                 }
02679                 if (dest[BYTE4_XOR_LE(tbaseaddr + 2)] != ((data >> 16) & 0xff)) {
02680                         dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff;
02681                         changed = true;
02682                 }
02683                 if (dest[BYTE4_XOR_LE(tbaseaddr + 3)] != ((data >> 24) & 0xff)) {
02684                         dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff;
02685                         changed = true;
02686                 }
02687 
02688                 if (changed && v->ogl && v->active) {
02689                         voodoo_ogl_texture_clear(t->lodoffset[lod],tmunum);
02690                         voodoo_ogl_texture_clear(t->lodoffset[t->lodmin],tmunum);
02691                 }
02692         }
02693 
02694         /* 16-bit texture case */
02695         else
02696         {
02697                 int lod, tt, ts;
02698                 UINT32 tbaseaddr;
02699                 UINT16 *dest;
02700 
02701                 /* extract info */
02702                 // tmunum = (offset >> 19) & 0x03;
02703                 lod = (offset >> 15) & 0x0f;
02704                 tt = (offset >> 7) & 0xff;
02705                 ts = (offset << 1) & 0xfe;
02706 
02707                 /* validate parameters */
02708                 if (lod > 8)
02709                         return 0;
02710 
02711                 /* compute the base address */
02712                 tbaseaddr = t->lodoffset[lod];
02713                 tbaseaddr += (UINT32)(2l * ((long)tt * (((long)t->wmask >> lod) + 1l) + (long)ts));
02714 
02715                 if (LOG_TEXTURE_RAM) LOG(LOG_VOODOO,LOG_WARN)("Texture 16-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data);
02716 
02717                 /* write the two words in little-endian order */
02718                 dest = (UINT16 *)t->ram;
02719                 tbaseaddr &= t->mask;
02720                 tbaseaddr >>= 1;
02721 
02722                 bool changed = false;
02723                 if (dest[BYTE_XOR_LE(tbaseaddr + 0)] != ((data >> 0) & 0xffff)) {
02724                         dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff;
02725                         changed = true;
02726                 }
02727                 if (dest[BYTE_XOR_LE(tbaseaddr + 1)] != ((data >> 16) & 0xffff)) {
02728                         dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff;
02729                         changed = true;
02730                 }
02731 
02732                 if (changed && v->ogl && v->active) {
02733                         voodoo_ogl_texture_clear(t->lodoffset[lod],tmunum);
02734                         voodoo_ogl_texture_clear(t->lodoffset[t->lodmin],tmunum);
02735                 }
02736         }
02737 
02738         return 0;
02739 }
02740 
02741 
02742 
02743 /*************************************
02744  *
02745  *  Handle a register read
02746  *
02747  *************************************/
02748 
02749 UINT32 register_r(UINT32 offset)
02750 {
02751         UINT32 regnum  = (offset) & 0xff;
02752 
02753 //      LOG(LOG_VOODOO,LOG_WARN)("Voodoo:read chip %x reg %x (%s)", chips, regnum<<2, voodoo_reg_name[regnum]);
02754 
02755         /* first make sure this register is readable */
02756         if (!(v->regaccess[regnum] & REGISTER_READ))
02757         {
02758                 return 0xffffffff;
02759         }
02760 
02761         UINT32 result;
02762 
02763         /* default result is the FBI register value */
02764         result = v->reg[regnum].u;
02765 
02766         /* some registers are dynamic; compute them */
02767         switch (regnum)
02768         {
02769                 case status:
02770                         CPU_Core_Dyn_X86_SaveDHFPUState();
02771 
02772                         /* start with a blank slate */
02773                         result = 0;
02774 
02775                         /* bits 5:0 are the PCI FIFO free space */
02776                         result |= 0x3fu << 0u;
02777 
02778                         /* bit 6 is the vertical retrace */
02779                         //result |= v->fbi.vblank << 6;
02780                         result |= (Voodoo_GetRetrace() ? 0x40u : 0u);
02781 
02782                         if (v->pci.op_pending) {
02783                                 /* bit 7 is FBI graphics engine busy */
02784                                 result |= 1 << 7;
02785                                 /* bit 8 is TREX busy */
02786                                 result |= 1 << 8;
02787                                 /* bit 9 is overall busy */
02788                                 result |= 1 << 9;
02789                         }
02790 
02791                         /* bits 11:10 specifies which buffer is visible */
02792                         result |= (UINT32)(v->fbi.frontbuf << 10);
02793 
02794                         /* bits 27:12 indicate memory FIFO freespace */
02795                         result |= 0xffffu << 12u;
02796 
02797                         /* bits 30:28 are the number of pending swaps */
02798                         result |= 0u << 28u;
02799 
02800                         /* bit 31 is not used */
02801 
02802                         CPU_Core_Dyn_X86_RestoreDHFPUState();
02803 
02804                         break;
02805 
02806                 case hvRetrace:
02807                         if (v->type < VOODOO_2)
02808                                 break;
02809 
02810                         CPU_Core_Dyn_X86_SaveDHFPUState();
02811 
02812                         /* start with a blank slate */
02813                         result = 0;
02814 
02815                         result |= ((Bit32u)(Voodoo_GetVRetracePosition() * 0x1fff)) & 0x1fff;
02816                         result |= (((Bit32u)(Voodoo_GetHRetracePosition() * 0x7ff)) & 0x7ff) << 16;
02817 
02818                         CPU_Core_Dyn_X86_RestoreDHFPUState();
02819                         break;
02820 
02821                 /* bit 2 of the initEnable register maps this to dacRead */
02822                 case fbiInit2:
02823                         if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
02824                                 result = v->dac.read_result;
02825                         break;
02826 
02827 /*              case fbiInit3:
02828                         if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
02829                                 result = 0;
02830                         break;
02831 
02832                 case fbiInit6:
02833                         if (v->type < VOODOO_2)
02834                                 break;
02835                         result &= 0xffffe7ff;
02836                         result |= 0x1000;
02837                         break; */
02838 
02839                 /* all counters are 24-bit only */
02840                 case fbiPixelsIn:
02841                 case fbiChromaFail:
02842                 case fbiZfuncFail:
02843                 case fbiAfuncFail:
02844                 case fbiPixelsOut:
02845                         update_statistics(v, true);
02846                 case fbiTrianglesOut:
02847                         result = v->reg[regnum].u & 0xffffff;
02848                         break;
02849 
02850         }
02851 
02852         return result;
02853 }
02854 
02855 
02856 
02857 /*************************************
02858  *
02859  *  Handle an LFB read
02860  *
02861  *************************************/
02862 UINT32 lfb_r(UINT32 offset)
02863 {
02864         LOG(LOG_VOODOO,LOG_WARN)("Voodoo:read LFB offset %X", offset);
02865         UINT16 *buffer;
02866         UINT32 bufmax;
02867         UINT32 data;
02868         int x, y, scry;
02869         UINT32 destbuf;
02870 
02871         /* compute X,Y */
02872         x = (offset << 1) & 0x3fe;
02873         y = (offset >> 9) & 0x3ff;
02874 
02875         /* select the target buffer */
02876         destbuf = LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u);
02877         switch (destbuf)
02878         {
02879                 case 0:                 /* front buffer */
02880                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
02881                         bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
02882                         break;
02883 
02884                 case 1:                 /* back buffer */
02885                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
02886                         bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
02887                         break;
02888 
02889                 case 2:                 /* aux buffer */
02890                         if (v->fbi.auxoffs == (UINT32)(~0))
02891                                 return 0xffffffff;
02892                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
02893                         bufmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
02894                         break;
02895 
02896                 default:                /* reserved */
02897                         return 0xffffffff;
02898         }
02899 
02900         /* determine the screen Y */
02901         scry = y;
02902         if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
02903                 scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02904 
02905         if (v->ogl && v->active) {
02906                 data = voodoo_ogl_read_pixel(x, scry+1);
02907         } else {
02908                 /* advance pointers to the proper row */
02909                 UINT32 bufoffs = (unsigned long)((long)scry * (long)v->fbi.rowpixels + (long)x);
02910                 if (bufoffs >= bufmax){
02911                         LOG_MSG("LFB_R: Buffer offset out of bounds x=%i y=%i offset=%08X bufoffs=%08X\n", x, y, offset, (UINT32) bufoffs);
02912                         return 0xffffffff;
02913                 }
02914 
02915                 /* compute the data */
02916                 data = (unsigned int)buffer[bufoffs + 0u] | (unsigned int)(buffer[bufoffs + 1u] << 16u);
02917         }
02918 
02919         /* word swapping */
02920         if (LFBMODE_WORD_SWAP_READS(v->reg[lfbMode].u))
02921                 data = (data << 16u) | (data >> 16u);
02922 
02923         /* byte swizzling */
02924         if (LFBMODE_BYTE_SWIZZLE_READS(v->reg[lfbMode].u))
02925                 data = FLIPENDIAN_INT32(data);
02926 
02927         if (LOG_LFB) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data);
02928         return data;
02929 }
02930 
02931 
02932 void voodoo_w(UINT32 offset, UINT32 data, UINT32 mask) {
02933         if ((offset & (0xc00000/4)) == 0)
02934                 register_w(offset, data);
02935         else if ((offset & (0x800000/4)) == 0)
02936                 lfb_w(offset, data, mask);
02937         else
02938                 texture_w(offset, data);
02939 }
02940 
02941 UINT32 voodoo_r(UINT32 offset) {
02942         if ((offset & (0xc00000/4)) == 0)
02943                 return register_r(offset);
02944         else if ((offset & (0x800000/4)) == 0)
02945                 return lfb_r(offset);
02946 
02947         return 0xffffffff;
02948 }
02949 
02950 
02951 
02952 /***************************************************************************
02953     DEVICE INTERFACE
02954 ***************************************************************************/
02955 
02956 /*-------------------------------------------------
02957     device start callback
02958 -------------------------------------------------*/
02959 
02960 void voodoo_init(int type) {
02961         v->active = false;
02962 
02963         v->type = VOODOO_1_DTMU;
02964 
02965         switch (type) {
02966                 case VOODOO_1:
02967                         break;
02968                 case VOODOO_1_DTMU:
02969                         v->type = VOODOO_1_DTMU;
02970                         break;
02971                 case VOODOO_2:
02972                         v->type = VOODOO_2;
02973                         break;
02974                 default:
02975                         LOG_MSG("invalid voodoo card type initialization [%x]",type);
02976                         break;
02977         }
02978 
02979         memset(v->reg, 0, sizeof(v->reg));
02980 
02981         v->fbi.vblank_flush_pending = false;
02982         v->pci.op_pending = false;
02983         v->dac.read_result = 0;
02984 
02985         v->output_on = false;
02986         v->clock_enabled = false;
02987         v->ogl_dimchange = true;
02988         v->send_config = false;
02989 
02990         memset(v->dac.reg, 0, sizeof(v->dac.reg));
02991 
02992         v->next_rasterizer = 0;
02993         for (UINT32 rct=0; rct<MAX_RASTERIZERS; rct++)
02994                 v->rasterizer[rct] = raster_info();
02995 
02996         v->thread_stats = new stats_block[1];
02997         v->thread_stats[0].pixels_in = 0;
02998         v->thread_stats[0].pixels_out = 0;
02999         v->thread_stats[0].chroma_fail = 0;
03000         v->thread_stats[0].zfunc_fail = 0;
03001         v->thread_stats[0].afunc_fail = 0;
03002         v->thread_stats[0].clip_fail = 0;
03003         v->thread_stats[0].stipple_count = 0;
03004 
03005         v->alt_regmap = false;
03006         v->regnames = voodoo_reg_name;
03007 
03008         /* create a table of precomputed 1/n and log2(n) values */
03009         /* n ranges from 1.0000 to 2.0000 */
03010         for (UINT32 val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++)
03011         {
03012                 UINT32 value = (1 << RECIPLOG_LOOKUP_BITS) + val;
03013                 voodoo_reciplog[val*2 + 0] = (1u << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
03014                 voodoo_reciplog[val*2 + 1] = (UINT32)(LOGB2((double)value / (double)(1u << RECIPLOG_LOOKUP_BITS)) * (double)(1u << RECIPLOG_LOOKUP_PREC));
03015         }
03016 
03017         for (UINT32 val = 0; val < RASTER_HASH_SIZE; val++)
03018                 v->raster_hash[val] = NULL;
03019 
03020         /* create dithering tables */
03021         for (UINT32 val = 0; val < 256*16*2; val++)
03022         {
03023                 int g = (val >> 0) & 1;
03024                 int x = (val >> 1) & 3;
03025                 int color = (val >> 3) & 0xff;
03026                 int y = (val >> 11) & 3;
03027 
03028                 if (!g)
03029                 {
03030                         dither4_lookup[val] = (UINT8)(DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3);
03031                         dither2_lookup[val] = (UINT8)(DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3);
03032                 }
03033                 else
03034                 {
03035                         dither4_lookup[val] = (UINT8)(DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2);
03036                         dither2_lookup[val] = (UINT8)(DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2);
03037                 }
03038         }
03039 
03040         v->tmu_config = 0x11;   // revision 1
03041 
03042         UINT32 fbmemsize = 0;
03043         UINT32 tmumem0 = 0;
03044         UINT32 tmumem1 = 0;
03045 
03046         /* configure type-specific values */
03047         switch (v->type)
03048         {
03049                 case VOODOO_1:
03050                         v->regaccess = voodoo_register_access;
03051                         fbmemsize = 2;
03052                         tmumem0 = 2;
03053                         break;
03054 
03055                 case VOODOO_1_DTMU:
03056                         v->regaccess = voodoo_register_access;
03057                         fbmemsize = 4;
03058                         tmumem0 = 4;
03059                         tmumem1 = 4;
03060                         break;
03061 
03062                 case VOODOO_2:
03063                         v->regaccess = voodoo2_register_access;
03064                         fbmemsize = 4;
03065                         tmumem0 = 4;
03066                         tmumem1 = 4;
03067                         v->tmu_config |= 0x800;
03068                         break;
03069 
03070                 default:
03071                         E_Exit("Unsupported voodoo card in voodoo_start!");
03072                         break;
03073         }
03074 
03075         if (tmumem1 != 0)
03076                 v->tmu_config |= 0xc0;  // two TMUs
03077 
03078         v->chipmask = 0x01;
03079 
03080         /* set up the PCI FIFO */
03081         v->pci.fifo.size = 64*2;
03082 
03083         /* set up frame buffer */
03084         init_fbi(v, &v->fbi, (int)(fbmemsize << 20));
03085 
03086         v->fbi.rowpixels = v->fbi.width;
03087 
03088         v->tmu[0].ncc[0].palette = NULL;
03089         v->tmu[0].ncc[1].palette = NULL;
03090         v->tmu[1].ncc[0].palette = NULL;
03091         v->tmu[1].ncc[1].palette = NULL;
03092         v->tmu[0].ncc[0].palettea = NULL;
03093         v->tmu[0].ncc[1].palettea = NULL;
03094         v->tmu[1].ncc[0].palettea = NULL;
03095         v->tmu[1].ncc[1].palettea = NULL;
03096 
03097         v->tmu[0].ram = NULL;
03098         v->tmu[1].ram = NULL;
03099         v->tmu[0].lookup = NULL;
03100         v->tmu[1].lookup = NULL;
03101 
03102         /* build shared TMU tables */
03103         init_tmu_shared(&v->tmushare);
03104 
03105         /* set up the TMUs */
03106         init_tmu(v, &v->tmu[0], &v->reg[0x100], (int)(tmumem0 << 20));
03107         v->chipmask |= 0x02;
03108         if (tmumem1 != 0)
03109         {
03110                 init_tmu(v, &v->tmu[1], &v->reg[0x200], (int)(tmumem1 << 20));
03111                 v->chipmask |= 0x04;
03112                 v->tmu_config |= 0x40;
03113         }
03114 
03115         /* initialize some registers */
03116         v->pci.init_enable = 0;
03117         v->reg[fbiInit0].u = (UINT32)((1 << 4) | (0x10 << 6));
03118         v->reg[fbiInit1].u = (UINT32)((1 << 1) | (1 << 8) | (1 << 12) | (2 << 20));
03119         v->reg[fbiInit2].u = (UINT32)((1 << 6) | (0x100 << 23));
03120         v->reg[fbiInit3].u = (UINT32)((2 << 13) | (0xf << 17));
03121         v->reg[fbiInit4].u = (UINT32)(1 << 0);
03122 
03123         /* do a soft reset to reset everything else */
03124         soft_reset(v);
03125 
03126         recompute_video_memory(v);
03127 }
03128 
03129 void voodoo_shutdown() {
03130         if (v->ogl)
03131                 voodoo_ogl_shutdown(v);
03132 
03133         if (v!=NULL) {
03134                 free(v->fbi.ram);
03135                 if (v->tmu[0].ram != NULL) {
03136                         free(v->tmu[0].ram);
03137                         v->tmu[0].ram = NULL;
03138                 }
03139                 if (v->tmu[1].ram != NULL) {
03140                         free(v->tmu[1].ram);
03141                         v->tmu[1].ram = NULL;
03142                 }
03143                 delete[] v->thread_stats;
03144                 v->active=false;
03145         }
03146 }
03147 
03148 
03149 /***************************************************************************
03150     COMMAND HANDLERS
03151 ***************************************************************************/
03152 
03153 /*-------------------------------------------------
03154     fastfill - execute the 'fastfill'
03155     command
03156 -------------------------------------------------*/
03157 
03158 void fastfill(voodoo_state *v)
03159 {
03160         int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
03161         int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
03162         int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
03163         int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
03164 
03165         poly_extent extents[64];
03166         UINT16 dithermatrix[16];
03167         UINT16 *drawbuf = NULL;
03168         int extnum, y;
03169 
03170         /* if we're not clearing either, take no time */
03171         if (!FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u))
03172                 return;
03173 
03174         /* are we clearing the RGB buffer? */
03175         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
03176         {
03177                 /* determine the draw buffer */
03178                 int destbuf = FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
03179                 switch (destbuf)
03180                 {
03181                         case 0:         /* front buffer */
03182                                 drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
03183                                 break;
03184 
03185                         case 1:         /* back buffer */
03186                                 drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
03187                                 break;
03188 
03189                         default:        /* reserved */
03190                                 break;
03191                 }
03192 
03193                 /* determine the dither pattern */
03194                 for (y = 0; y < 4; y++)
03195                 {
03196                         DECLARE_DITHER_POINTERS_NO_DITHER_VAR;
03197                         COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y);
03198                         for (int x = 0; x < 4; x++)
03199                         {
03200                                 int r = v->reg[color1].rgb.r;
03201                                 int g = v->reg[color1].rgb.g;
03202                                 int b = v->reg[color1].rgb.b;
03203 
03204                                 APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, r, g, b);
03205                                 dithermatrix[y*4 + x] = (UINT16)((r << 11) | (g << 5) | b);
03206                         }
03207                 }
03208         }
03209 
03210         /* fill in a block of extents */
03211         extents[0].startx = sx;
03212         extents[0].stopx = ex;
03213         for (extnum = 1; (size_t)extnum < ARRAY_LENGTH(extents); extnum++)
03214                 extents[extnum] = extents[0];
03215 
03216         poly_extra_data *extra = new poly_extra_data;
03217 
03218         if (v->ogl && v->active) {
03219                 voodoo_ogl_fastfill();
03220         } else {
03221 
03222                 /* iterate over blocks of extents */
03223                 for (y = sy; y < ey; y += (int)ARRAY_LENGTH(extents))
03224                 {
03225                         int count = (int)MIN(((size_t)(ey - y)), ARRAY_LENGTH(extents));
03226 
03227                         extra->state = v;
03228                         memcpy(extra->dither, dithermatrix, sizeof(extra->dither));
03229 
03230                         poly_render_triangle_custom(drawbuf, y, count, extents, extra);
03231                 }
03232         }
03233         delete extra;
03234 }
03235 
03236 
03237 /*-------------------------------------------------
03238     swapbuffer - execute the 'swapbuffer'
03239     command
03240 -------------------------------------------------*/
03241 
03242 void swapbuffer(voodoo_state *v, UINT32 data)
03243 {
03244         /* set the don't swap value for Voodoo 2 */
03245         v->fbi.vblank_dont_swap = ((data >> 9) & 1)>0;
03246 
03247         voodoo_swap_buffers(v);
03248 }
03249 
03250 
03251 /*-------------------------------------------------
03252     triangle - execute the 'triangle'
03253     command
03254 -------------------------------------------------*/
03255 
03256 void triangle(voodoo_state *v)
03257 {
03258         int texcount = 0;
03259         UINT16 *drawbuf;
03260         int destbuf;
03261 
03262         /* determine the number of TMUs involved */
03263         texcount = 0;
03264         if (!FBIINIT3_DISABLE_TMUS(v->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(v->reg[fbzColorPath].u))
03265         {
03266                 texcount = 1;
03267                 if (v->chipmask & 0x04)
03268                         texcount = 2;
03269         }
03270 
03271         /* perform subpixel adjustments */
03272         // ????????
03273         if (!v->ogl && FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
03274 //      if (FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
03275         {
03276                 INT32 dx = 8 - (v->fbi.ax & 15);
03277                 INT32 dy = 8 - (v->fbi.ay & 15);
03278 
03279                 /* adjust iterated R,G,B,A and W/Z */
03280                 v->fbi.startr += (dy * v->fbi.drdy + dx * v->fbi.drdx) >> 4;
03281                 v->fbi.startg += (dy * v->fbi.dgdy + dx * v->fbi.dgdx) >> 4;
03282                 v->fbi.startb += (dy * v->fbi.dbdy + dx * v->fbi.dbdx) >> 4;
03283                 v->fbi.starta += (dy * v->fbi.dady + dx * v->fbi.dadx) >> 4;
03284                 v->fbi.startw += (dy * v->fbi.dwdy + dx * v->fbi.dwdx) >> 4;
03285                 v->fbi.startz += mul_32x32_shift(dy, v->fbi.dzdy, 4) + mul_32x32_shift(dx, v->fbi.dzdx, 4);
03286 
03287                 /* adjust iterated W/S/T for TMU 0 */
03288                 if (texcount >= 1)
03289                 {
03290                         v->tmu[0].startw += (dy * v->tmu[0].dwdy + dx * v->tmu[0].dwdx) >> 4;
03291                         v->tmu[0].starts += (dy * v->tmu[0].dsdy + dx * v->tmu[0].dsdx) >> 4;
03292                         v->tmu[0].startt += (dy * v->tmu[0].dtdy + dx * v->tmu[0].dtdx) >> 4;
03293 
03294                         /* adjust iterated W/S/T for TMU 1 */
03295                         if (texcount >= 2)
03296                         {
03297                                 v->tmu[1].startw += (dy * v->tmu[1].dwdy + dx * v->tmu[1].dwdx) >> 4;
03298                                 v->tmu[1].starts += (dy * v->tmu[1].dsdy + dx * v->tmu[1].dsdx) >> 4;
03299                                 v->tmu[1].startt += (dy * v->tmu[1].dtdy + dx * v->tmu[1].dtdx) >> 4;
03300                         }
03301                 }
03302         }
03303 
03304         /* determine the draw buffer */
03305         destbuf = FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
03306         switch (destbuf)
03307         {
03308                 case 0:         /* front buffer */
03309                         drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
03310                         break;
03311 
03312                 case 1:         /* back buffer */
03313                         drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
03314                         break;
03315 
03316                 default:        /* reserved */
03317                         return;
03318         }
03319 
03320         /* find a rasterizer that matches our current state */
03321         triangle_create_work_item(v, drawbuf, texcount);
03322 
03323         /* update stats */
03324         v->reg[fbiTrianglesOut].u++;
03325 }
03326 
03327 
03328 /*-------------------------------------------------
03329     begin_triangle - execute the 'beginTri'
03330     command
03331 -------------------------------------------------*/
03332 
03333 static void begin_triangle(voodoo_state *v)
03334 {
03335         setup_vertex *sv = &v->fbi.svert[2];
03336 
03337         /* extract all the data from registers */
03338         sv->x = v->reg[sVx].f;
03339         sv->y = v->reg[sVy].f;
03340         sv->wb = v->reg[sWb].f;
03341         sv->w0 = v->reg[sWtmu0].f;
03342         sv->s0 = v->reg[sS_W0].f;
03343         sv->t0 = v->reg[sT_W0].f;
03344         sv->w1 = v->reg[sWtmu1].f;
03345         sv->s1 = v->reg[sS_Wtmu1].f;
03346         sv->t1 = v->reg[sT_Wtmu1].f;
03347         sv->a = v->reg[sAlpha].f;
03348         sv->r = v->reg[sRed].f;
03349         sv->g = v->reg[sGreen].f;
03350         sv->b = v->reg[sBlue].f;
03351 
03352         /* spread it across all three verts and reset the count */
03353         v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2];
03354         v->fbi.sverts = 1;
03355 }
03356 
03357 
03358 /*-------------------------------------------------
03359     draw_triangle - execute the 'DrawTri'
03360     command
03361 -------------------------------------------------*/
03362 
03363 static void draw_triangle(voodoo_state *v)
03364 {
03365         setup_vertex *sv = &v->fbi.svert[2];
03366 
03367         /* for strip mode, shuffle vertex 1 down to 0 */
03368         if (!(v->reg[sSetupMode].u & (1 << 16)))
03369                 v->fbi.svert[0] = v->fbi.svert[1];
03370 
03371         /* copy 2 down to 1 regardless */
03372         v->fbi.svert[1] = v->fbi.svert[2];
03373 
03374         /* extract all the data from registers */
03375         sv->x = v->reg[sVx].f;
03376         sv->y = v->reg[sVy].f;
03377         sv->wb = v->reg[sWb].f;
03378         sv->w0 = v->reg[sWtmu0].f;
03379         sv->s0 = v->reg[sS_W0].f;
03380         sv->t0 = v->reg[sT_W0].f;
03381         sv->w1 = v->reg[sWtmu1].f;
03382         sv->s1 = v->reg[sS_Wtmu1].f;
03383         sv->t1 = v->reg[sT_Wtmu1].f;
03384         sv->a = v->reg[sAlpha].f;
03385         sv->r = v->reg[sRed].f;
03386         sv->g = v->reg[sGreen].f;
03387         sv->b = v->reg[sBlue].f;
03388 
03389         /* if we have enough verts, go ahead and draw */
03390         if (++v->fbi.sverts >= 3)
03391                 setup_and_draw_triangle(v);
03392 }
03393 
03394 
03395 /*-------------------------------------------------
03396     setup_and_draw_triangle - process the setup
03397     parameters and render the triangle
03398 -------------------------------------------------*/
03399 
03400 static void setup_and_draw_triangle(voodoo_state *v)
03401 {
03402         float dx1, dy1, dx2, dy2;
03403         float divisor, tdiv;
03404 
03405         /* grab the X/Ys at least */
03406         v->fbi.ax = (INT16)(v->fbi.svert[0].x * 16.0);
03407         v->fbi.ay = (INT16)(v->fbi.svert[0].y * 16.0);
03408         v->fbi.bx = (INT16)(v->fbi.svert[1].x * 16.0);
03409         v->fbi.by = (INT16)(v->fbi.svert[1].y * 16.0);
03410         v->fbi.cx = (INT16)(v->fbi.svert[2].x * 16.0);
03411         v->fbi.cy = (INT16)(v->fbi.svert[2].y * 16.0);
03412 
03413         /* compute the divisor */
03414         divisor = 1.0f / ((v->fbi.svert[0].x - v->fbi.svert[1].x) * (v->fbi.svert[0].y - v->fbi.svert[2].y) -
03415                                           (v->fbi.svert[0].x - v->fbi.svert[2].x) * (v->fbi.svert[0].y - v->fbi.svert[1].y));
03416 
03417         /* backface culling */
03418         if (v->reg[sSetupMode].u & 0x20000)
03419         {
03420                 int culling_sign = (v->reg[sSetupMode].u >> 18) & 1;
03421                 int divisor_sign = (divisor < 0);
03422 
03423                 /* if doing strips and ping pong is enabled, apply the ping pong */
03424                 if ((v->reg[sSetupMode].u & 0x90000) == 0x00000)
03425                         culling_sign ^= (v->fbi.sverts - 3) & 1;
03426 
03427                 /* if our sign matches the culling sign, we're done for */
03428                 if (divisor_sign == culling_sign)
03429                         return;
03430         }
03431 
03432         /* compute the dx/dy values */
03433         dx1 = v->fbi.svert[0].y - v->fbi.svert[2].y;
03434         dx2 = v->fbi.svert[0].y - v->fbi.svert[1].y;
03435         dy1 = v->fbi.svert[0].x - v->fbi.svert[1].x;
03436         dy2 = v->fbi.svert[0].x - v->fbi.svert[2].x;
03437 
03438         /* set up R,G,B */
03439         tdiv = divisor * 4096.0f;
03440         if (v->reg[sSetupMode].u & (1 << 0))
03441         {
03442                 v->fbi.startr = (INT32)(v->fbi.svert[0].r * 4096.0f);
03443                 v->fbi.drdx = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[1].r) * dx1 - (v->fbi.svert[0].r - v->fbi.svert[2].r) * dx2) * tdiv);
03444                 v->fbi.drdy = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[2].r) * dy1 - (v->fbi.svert[0].r - v->fbi.svert[1].r) * dy2) * tdiv);
03445                 v->fbi.startg = (INT32)(v->fbi.svert[0].g * 4096.0f);
03446                 v->fbi.dgdx = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[1].g) * dx1 - (v->fbi.svert[0].g - v->fbi.svert[2].g) * dx2) * tdiv);
03447                 v->fbi.dgdy = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[2].g) * dy1 - (v->fbi.svert[0].g - v->fbi.svert[1].g) * dy2) * tdiv);
03448                 v->fbi.startb = (INT32)(v->fbi.svert[0].b * 4096.0f);
03449                 v->fbi.dbdx = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[1].b) * dx1 - (v->fbi.svert[0].b - v->fbi.svert[2].b) * dx2) * tdiv);
03450                 v->fbi.dbdy = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[2].b) * dy1 - (v->fbi.svert[0].b - v->fbi.svert[1].b) * dy2) * tdiv);
03451         }
03452 
03453         /* set up alpha */
03454         if (v->reg[sSetupMode].u & (1 << 1))
03455         {
03456                 v->fbi.starta = (INT32)(v->fbi.svert[0].a * 4096.0);
03457                 v->fbi.dadx = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[1].a) * dx1 - (v->fbi.svert[0].a - v->fbi.svert[2].a) * dx2) * tdiv);
03458                 v->fbi.dady = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[2].a) * dy1 - (v->fbi.svert[0].a - v->fbi.svert[1].a) * dy2) * tdiv);
03459         }
03460 
03461         /* set up Z */
03462         if (v->reg[sSetupMode].u & (1 << 2))
03463         {
03464                 v->fbi.startz = (INT32)(v->fbi.svert[0].z * 4096.0);
03465                 v->fbi.dzdx = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[1].z) * dx1 - (v->fbi.svert[0].z - v->fbi.svert[2].z) * dx2) * tdiv);
03466                 v->fbi.dzdy = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[2].z) * dy1 - (v->fbi.svert[0].z - v->fbi.svert[1].z) * dy2) * tdiv);
03467         }
03468 
03469         /* set up Wb */
03470         tdiv = divisor * 65536.0f * 65536.0f;
03471         if (v->reg[sSetupMode].u & (1 << 3))
03472         {
03473                 v->fbi.startw = v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].wb * 65536.0f * 65536.0f);
03474                 v->fbi.dwdx = v->tmu[0].dwdx = v->tmu[1].dwdx = (INT64)(((v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dx1 - (v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dx2) * tdiv);
03475                 v->fbi.dwdy = v->tmu[0].dwdy = v->tmu[1].dwdy = (INT64)(((v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dy1 - (v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dy2) * tdiv);
03476         }
03477 
03478         /* set up W0 */
03479         if (v->reg[sSetupMode].u & (1 << 4))
03480         {
03481                 v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].w0 * 65536.0f * 65536.0f);
03482                 v->tmu[0].dwdx = v->tmu[1].dwdx = (INT64)(((v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dx1 - (v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dx2) * tdiv);
03483                 v->tmu[0].dwdy = v->tmu[1].dwdy = (INT64)(((v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dy1 - (v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dy2) * tdiv);
03484         }
03485 
03486         /* set up S0,T0 */
03487         if (v->reg[sSetupMode].u & (1 << 5))
03488         {
03489                 v->tmu[0].starts = v->tmu[1].starts = (INT64)(v->fbi.svert[0].s0 * 65536.0f * 65536.0f);
03490                 v->tmu[0].dsdx = v->tmu[1].dsdx = (INT64)(((v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dx1 - (v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dx2) * tdiv);
03491                 v->tmu[0].dsdy = v->tmu[1].dsdy = (INT64)(((v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dy1 - (v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dy2) * tdiv);
03492                 v->tmu[0].startt = v->tmu[1].startt = (INT64)(v->fbi.svert[0].t0 * 65536.0f * 65536.0f);
03493                 v->tmu[0].dtdx = v->tmu[1].dtdx = (INT64)(((v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dx1 - (v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dx2) * tdiv);
03494                 v->tmu[0].dtdy = v->tmu[1].dtdy = (INT64)(((v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dy1 - (v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dy2) * tdiv);
03495         }
03496 
03497         /* set up W1 */
03498         if (v->reg[sSetupMode].u & (1 << 6))
03499         {
03500                 v->tmu[1].startw = (INT64)(v->fbi.svert[0].w1 * 65536.0f * 65536.0f);
03501                 v->tmu[1].dwdx = (INT64)(((v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dx1 - (v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dx2) * tdiv);
03502                 v->tmu[1].dwdy = (INT64)(((v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dy1 - (v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dy2) * tdiv);
03503         }
03504 
03505         /* set up S1,T1 */
03506         if (v->reg[sSetupMode].u & (1 << 7))
03507         {
03508                 v->tmu[1].starts = (INT64)(v->fbi.svert[0].s1 * 65536.0f * 65536.0f);
03509                 v->tmu[1].dsdx = (INT64)(((v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dx1 - (v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dx2) * tdiv);
03510                 v->tmu[1].dsdy = (INT64)(((v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dy1 - (v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dy2) * tdiv);
03511                 v->tmu[1].startt = (INT64)(v->fbi.svert[0].t1 * 65536.0f * 65536.0f);
03512                 v->tmu[1].dtdx = (INT64)(((v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dx1 - (v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dx2) * tdiv);
03513                 v->tmu[1].dtdy = (INT64)(((v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dy1 - (v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dy2) * tdiv);
03514         }
03515 
03516         /* draw the triangle */
03517         triangle(v);
03518 }
03519 
03520 
03521 /*-------------------------------------------------
03522     triangle_create_work_item - finish triangle
03523     setup and create the work item
03524 -------------------------------------------------*/
03525 
03526 void triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount)
03527 {
03528         poly_extra_data *extra = new poly_extra_data;
03529         raster_info *info  = find_rasterizer(v, texcount);
03530         poly_vertex vert[3];
03531 
03532         /* fill in the vertex data */
03533         vert[0].x = (float)v->fbi.ax * (1.0f / 16.0f);
03534         vert[0].y = (float)v->fbi.ay * (1.0f / 16.0f);
03535         vert[1].x = (float)v->fbi.bx * (1.0f / 16.0f);
03536         vert[1].y = (float)v->fbi.by * (1.0f / 16.0f);
03537         vert[2].x = (float)v->fbi.cx * (1.0f / 16.0f);
03538         vert[2].y = (float)v->fbi.cy * (1.0f / 16.0f);
03539 
03540         /* fill in the extra data */
03541         extra->state = v;
03542         extra->info = info;
03543 
03544         /* fill in triangle parameters */
03545         extra->ax = v->fbi.ax;
03546         extra->ay = v->fbi.ay;
03547         extra->startr = v->fbi.startr;
03548         extra->startg = v->fbi.startg;
03549         extra->startb = v->fbi.startb;
03550         extra->starta = v->fbi.starta;
03551         extra->startz = v->fbi.startz;
03552         extra->startw = v->fbi.startw;
03553         extra->drdx = v->fbi.drdx;
03554         extra->dgdx = v->fbi.dgdx;
03555         extra->dbdx = v->fbi.dbdx;
03556         extra->dadx = v->fbi.dadx;
03557         extra->dzdx = v->fbi.dzdx;
03558         extra->dwdx = v->fbi.dwdx;
03559         extra->drdy = v->fbi.drdy;
03560         extra->dgdy = v->fbi.dgdy;
03561         extra->dbdy = v->fbi.dbdy;
03562         extra->dady = v->fbi.dady;
03563         extra->dzdy = v->fbi.dzdy;
03564         extra->dwdy = v->fbi.dwdy;
03565 
03566         /* fill in texture 0 parameters */
03567         if (texcount > 0)
03568         {
03569                 extra->starts0 = v->tmu[0].starts;
03570                 extra->startt0 = v->tmu[0].startt;
03571                 extra->startw0 = v->tmu[0].startw;
03572                 extra->ds0dx = v->tmu[0].dsdx;
03573                 extra->dt0dx = v->tmu[0].dtdx;
03574                 extra->dw0dx = v->tmu[0].dwdx;
03575                 extra->ds0dy = v->tmu[0].dsdy;
03576                 extra->dt0dy = v->tmu[0].dtdy;
03577                 extra->dw0dy = v->tmu[0].dwdy;
03578                 extra->lodbase0 = prepare_tmu(&v->tmu[0]);
03579 
03580                 /* fill in texture 1 parameters */
03581                 if (texcount > 1)
03582                 {
03583                         extra->starts1 = v->tmu[1].starts;
03584                         extra->startt1 = v->tmu[1].startt;
03585                         extra->startw1 = v->tmu[1].startw;
03586                         extra->ds1dx = v->tmu[1].dsdx;
03587                         extra->dt1dx = v->tmu[1].dtdx;
03588                         extra->dw1dx = v->tmu[1].dwdx;
03589                         extra->ds1dy = v->tmu[1].dsdy;
03590                         extra->dt1dy = v->tmu[1].dtdy;
03591                         extra->dw1dy = v->tmu[1].dwdy;
03592                         extra->lodbase1 = prepare_tmu(&v->tmu[1]);
03593                 }
03594         }
03595 
03596         extra->texcount = (unsigned int)texcount;
03597         extra->r_fbzColorPath = v->reg[fbzColorPath].u;
03598         extra->r_fbzMode = v->reg[fbzMode].u;
03599         extra->r_alphaMode = v->reg[alphaMode].u;
03600         extra->r_fogMode = v->reg[fogMode].u;
03601         extra->r_textureMode0 = (INT32)v->tmu[0].reg[textureMode].u;
03602         if (v->tmu[1].ram != NULL) extra->r_textureMode1 = (INT32)v->tmu[1].reg[textureMode].u;
03603 
03604         info->polys++;
03605 
03606         if (palette_changed && v->ogl && v->active) {
03607                 voodoo_ogl_invalidate_paltex();
03608                 palette_changed = false;
03609         }
03610 
03611         if (v->ogl && v->active) {
03612                 if (extra->info==NULL)  {
03613                         delete extra;
03614                         return;
03615                 }
03616                 voodoo_ogl_draw_triangle(extra);
03617         } else {
03618                 poly_render_triangle(drawbuf, info->callback, &vert[0], &vert[1], &vert[2], extra);
03619         }
03620 
03621         delete extra;
03622 }
03623 
03624 /***************************************************************************
03625     RASTERIZER MANAGEMENT
03626 ***************************************************************************/
03627 
03628 /*-------------------------------------------------
03629     add_rasterizer - add a rasterizer to our
03630     hash table
03631 -------------------------------------------------*/
03632 
03633 static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo)
03634 {
03635         raster_info *info = &v->rasterizer[v->next_rasterizer++];
03636         unsigned int hash = compute_raster_hash(cinfo);
03637 
03638         if (v->next_rasterizer > MAX_RASTERIZERS)
03639                 E_Exit("Out of space for new rasterizers!");
03640 
03641         /* make a copy of the info */
03642         *info = *cinfo;
03643 
03644         /* fill in the data */
03645         info->hits = 0;
03646         info->polys = 0;
03647 
03648         /* hook us into the hash table */
03649         info->next = v->raster_hash[hash];
03650         v->raster_hash[hash] = info;
03651 
03652         if (LOG_RASTERIZERS)
03653                 LOG_MSG("Adding rasterizer @ %p : %08X %08X %08X %08X %08X %08X (hash=%d)\n",
03654                                 (void*)((uintptr_t)(info->callback)),
03655                                 info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode,
03656                                 info->eff_tex_mode_0, info->eff_tex_mode_1, hash);
03657 
03658         return info;
03659 }
03660 
03661 
03662 /*-------------------------------------------------
03663     find_rasterizer - find a rasterizer that
03664     matches  our current parameters and return
03665     it, creating a new one if necessary
03666 -------------------------------------------------*/
03667 
03668 static raster_info *find_rasterizer(voodoo_state *v, int texcount)
03669 {
03670         raster_info *info, *prev = NULL;
03671         raster_info curinfo;
03672         unsigned int hash;
03673 
03674         /* build an info struct with all the parameters */
03675         curinfo.eff_color_path = normalize_color_path(v->reg[fbzColorPath].u);
03676         curinfo.eff_alpha_mode = normalize_alpha_mode(v->reg[alphaMode].u);
03677         curinfo.eff_fog_mode = normalize_fog_mode(v->reg[fogMode].u);
03678         curinfo.eff_fbz_mode = normalize_fbz_mode(v->reg[fbzMode].u);
03679         curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(v->tmu[0].reg[textureMode].u) : 0xffffffff;
03680         curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(v->tmu[1].reg[textureMode].u) : 0xffffffff;
03681 
03682         /* compute the hash */
03683         hash = compute_raster_hash(&curinfo);
03684 
03685         /* find the appropriate hash entry */
03686         for (info = v->raster_hash[hash]; info; prev = info, info = info->next)
03687                 if (info->eff_color_path == curinfo.eff_color_path &&
03688                         info->eff_alpha_mode == curinfo.eff_alpha_mode &&
03689                         info->eff_fog_mode == curinfo.eff_fog_mode &&
03690                         info->eff_fbz_mode == curinfo.eff_fbz_mode &&
03691                         info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 &&
03692                         info->eff_tex_mode_1 == curinfo.eff_tex_mode_1)
03693                 {
03694                         /* got it, move us to the head of the list */
03695                         if (prev)
03696                         {
03697                                 prev->next = info->next;
03698                                 info->next = v->raster_hash[hash];
03699                                 v->raster_hash[hash] = info;
03700                         }
03701 
03702                         /* return the result */
03703                         return info;
03704                 }
03705 
03706         /* generate a new one using the generic entry */
03707         curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu;
03708         curinfo.is_generic = true;
03709         curinfo.display = 0;
03710         curinfo.polys = 0;
03711         curinfo.hits = 0;
03712         curinfo.next = 0;
03713         curinfo.shader_ready = false;
03714 
03715         return add_rasterizer(v, &curinfo);
03716 }
03717 
03718 
03719 /***************************************************************************
03720     GENERIC RASTERIZERS
03721 ***************************************************************************/
03722 
03723 /*-------------------------------------------------
03724     raster_fastfill - per-scanline
03725     implementation of the 'fastfill' command
03726 -------------------------------------------------*/
03727 
03728 static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata)
03729 {
03730         const poly_extra_data *extra = (const poly_extra_data *)extradata;
03731         v = extra->state;
03732         stats_block *stats = &v->thread_stats[0];
03733         INT32 startx = extent->startx;
03734         INT32 stopx = extent->stopx;
03735         int scry, x;
03736 
03737         /* determine the screen Y */
03738         scry = y;
03739         if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
03740                 scry = ((int)v->fbi.yorigin - y) & 0x3ff;
03741 
03742         /* fill this RGB row */
03743         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
03744         {
03745                 const UINT16 *ditherow = &extra->dither[(y & 3) * 4];
03746                 UINT64 expanded = *(UINT64 *)ditherow;
03747                 UINT16 *dest = (UINT16 *)destbase + ((uintptr_t)((long)scry * (long)v->fbi.rowpixels));
03748 
03749                 for (x = startx; x < stopx && (x & 3) != 0; x++)
03750                         dest[x] = ditherow[x & 3];
03751                 for ( ; x < (stopx & ~3); x += 4)
03752                         *(UINT64 *)&dest[x] = expanded;
03753                 for ( ; x < stopx; x++)
03754                         dest[x] = ditherow[x & 3];
03755                 stats->pixels_out += stopx - startx;
03756         }
03757 
03758         /* fill this dest buffer row */
03759         if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != (UINT32)(~0))
03760         {
03761                 UINT16 color = (UINT16)(v->reg[zaColor].u & 0xffff);
03762                 UINT64 expanded = ((UINT64)color << 48ull) | ((UINT64)color << 32ull) | ((UINT64)color << 16ull) | (UINT64)color;
03763                 UINT16 *dest = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + ((uintptr_t)((long)scry * (long)v->fbi.rowpixels));
03764 
03765                 if ((unsigned long)((long)v->fbi.auxoffs + 2l * ((long)scry * (long)v->fbi.rowpixels + (long)stopx)) >= v->fbi.mask) {
03766                         stopx = ((long)v->fbi.mask - (long)v->fbi.auxoffs) / 2l - (long)scry * (long)v->fbi.rowpixels;
03767                         if ((stopx < 0) || (stopx < startx)) return;
03768                 }
03769 
03770                 for (x = startx; x < stopx && (x & 3) != 0; x++)
03771                         dest[x] = color;
03772                 for ( ; x < (stopx & ~3); x += 4)
03773                         *(UINT64 *)&dest[x] = expanded;
03774                 for ( ; x < stopx; x++)
03775                         dest[x] = color;
03776         }
03777 }
03778 
03779 
03780 void voodoo_vblank_flush(void) {
03781         if (v->ogl)
03782                 voodoo_ogl_vblank_flush();
03783         v->fbi.vblank_flush_pending=false;
03784 }
03785 
03786 void voodoo_set_window(void) {
03787         if (v->ogl && v->active) {
03788                 voodoo_ogl_set_window(v);
03789         }
03790 }
03791 
03792 void voodoo_leave(void) {
03793         if (v->ogl) {
03794 #if C_OPENGL
03795                 voodoo_ogl_leave(true);
03796 #endif
03797         }
03798         v->active = false;
03799 }
03800 
03801 void voodoo_activate(void) {
03802         v->active = true;
03803 
03804         if (v->ogl) {
03805                 if (voodoo_ogl_init(v)) {
03806                         voodoo_ogl_clear();
03807                 } else {
03808                         v->ogl = false;
03809                         LOG_MSG("VOODOO: acceleration disabled");
03810                 }
03811         }
03812 }
03813 
03814 void voodoo_update_dimensions(void) {
03815         v->ogl_dimchange = false;
03816 
03817         if (v->ogl) {
03818 #if C_OPENGL
03819                 voodoo_ogl_update_dimensions();
03820 #endif
03821         }
03822 }