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 *dest, INT32 scanline, 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         voodoo_state *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         int r, g, b, i;
00929 
00930         /* generte all 256 possibilities */
00931         for (i = 0; i < 256; i++)
00932         {
00933                 int vi = (i >> 2) & 0x03;
00934                 int vq = (i >> 0) & 0x03;
00935 
00936                 /* start with the intensity */
00937                 r = g = b = n->y[(i >> 4) & 0x0f];
00938 
00939                 /* add the coloring */
00940                 r += n->ir[vi] + n->qr[vq];
00941                 g += n->ig[vi] + n->qg[vq];
00942                 b += n->ib[vi] + n->qb[vq];
00943 
00944                 /* clamp */
00945                 CLAMP(r, 0, 255);
00946                 CLAMP(g, 0, 255);
00947                 CLAMP(b, 0, 255);
00948 
00949                 /* fill in the table */
00950                 n->texel[i] = MAKE_ARGB(0xff, r, g, b);
00951         }
00952 
00953         /* no longer dirty */
00954         n->dirty = false;
00955 }
00956 
00957 
00958 
00959 /*************************************
00960  *
00961  *  Faux DAC implementation
00962  *
00963  *************************************/
00964 
00965 void dacdata_w(dac_state *d, UINT8 regnum, UINT8 data)
00966 {
00967         d->reg[regnum] = data;
00968 }
00969 
00970 
00971 void dacdata_r(dac_state *d, UINT8 regnum)
00972 {
00973         UINT8 result = 0xff;
00974 
00975         /* switch off the DAC register requested */
00976         switch (regnum)
00977         {
00978                 case 5:
00979                         /* this is just to make startup happy */
00980                         switch (d->reg[7])
00981                         {
00982                                 case 0x01:      result = 0x55; break;
00983                                 case 0x07:      result = 0x71; break;
00984                                 case 0x0b:      result = 0x79; break;
00985                         }
00986                         break;
00987 
00988                 default:
00989                         result = d->reg[regnum];
00990                         break;
00991         }
00992 
00993         /* remember the read result; it is fetched elsewhere */
00994         d->read_result = result;
00995 }
00996 
00997 
00998 
00999 /*************************************
01000  *
01001  *  Texuture parameter computation
01002  *
01003  *************************************/
01004 
01005 void recompute_texture_params(tmu_state *t)
01006 {
01007         int bppscale;
01008         UINT32 base;
01009         int lod;
01010 
01011         /* extract LOD parameters */
01012         t->lodmin = (INT32)TEXLOD_LODMIN(t->reg[tLOD].u) << 6;
01013         t->lodmax = (INT32)TEXLOD_LODMAX(t->reg[tLOD].u) << 6;
01014         t->lodbias = (INT8)(TEXLOD_LODBIAS(t->reg[tLOD].u) << 2) << 4;
01015 
01016         /* determine which LODs are present */
01017         t->lodmask = 0x1ff;
01018         if (TEXLOD_LOD_TSPLIT(t->reg[tLOD].u))
01019         {
01020                 if (!TEXLOD_LOD_ODD(t->reg[tLOD].u))
01021                         t->lodmask = 0x155;
01022                 else
01023                         t->lodmask = 0x0aa;
01024         }
01025 
01026         /* determine base texture width/height */
01027         t->wmask = t->hmask = 0xff;
01028         if (TEXLOD_LOD_S_IS_WIDER(t->reg[tLOD].u))
01029                 t->hmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
01030         else
01031                 t->wmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u);
01032 
01033         /* determine the bpp of the texture */
01034         bppscale = (int)TEXMODE_FORMAT(t->reg[textureMode].u) >> 3;
01035 
01036         /* start with the base of LOD 0 */
01037         if (t->texaddr_shift == 0 && (t->reg[texBaseAddr].u & 1))
01038                 LOG(LOG_VOODOO,LOG_WARN)("Tiled texture\n");
01039         base = (t->reg[texBaseAddr].u & t->texaddr_mask) << t->texaddr_shift;
01040         t->lodoffset[0] = base & t->mask;
01041 
01042         /* LODs 1-3 are different depending on whether we are in multitex mode */
01043         /* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */
01044         /* they want multitex mode when they really don't -- disable for now */
01045         if (0)//TEXLOD_TMULTIBASEADDR(t->reg[tLOD].u))
01046         {
01047                 base = (t->reg[texBaseAddr_1].u & t->texaddr_mask) << t->texaddr_shift;
01048                 t->lodoffset[1] = base & t->mask;
01049                 base = (t->reg[texBaseAddr_2].u & t->texaddr_mask) << t->texaddr_shift;
01050                 t->lodoffset[2] = base & t->mask;
01051                 base = (t->reg[texBaseAddr_3_8].u & t->texaddr_mask) << t->texaddr_shift;
01052                 t->lodoffset[3] = base & t->mask;
01053         }
01054         else
01055         {
01056                 if (t->lodmask & (1 << 0))
01057                         base += (((t->wmask >> 0) + 1) * ((t->hmask >> 0) + 1)) << bppscale;
01058                 t->lodoffset[1] = base & t->mask;
01059                 if (t->lodmask & (1 << 1))
01060                         base += (((t->wmask >> 1) + 1) * ((t->hmask >> 1) + 1)) << bppscale;
01061                 t->lodoffset[2] = base & t->mask;
01062                 if (t->lodmask & (1 << 2))
01063                         base += (((t->wmask >> 2) + 1) * ((t->hmask >> 2) + 1)) << bppscale;
01064                 t->lodoffset[3] = base & t->mask;
01065         }
01066 
01067         /* remaining LODs make sense */
01068         for (lod = 4; lod <= 8; lod++)
01069         {
01070                 if (t->lodmask & (1u << (lod - 1)))
01071                 {
01072                         UINT32 size = ((t->wmask >> (lod - 1)) + 1) * ((t->hmask >> (lod - 1)) + 1);
01073                         if (size < 4) size = 4;
01074                         base += size << bppscale;
01075                 }
01076                 t->lodoffset[lod] = base & t->mask;
01077         }
01078 
01079         /* set the NCC lookup appropriately */
01080         t->texel[1] = t->texel[9] = t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)].texel;
01081 
01082         /* pick the lookup table */
01083         t->lookup = t->texel[TEXMODE_FORMAT(t->reg[textureMode].u)];
01084 
01085         /* compute the detail parameters */
01086         t->detailmax = TEXDETAIL_DETAIL_MAX(t->reg[tDetail].u);
01087         t->detailbias = (INT8)(TEXDETAIL_DETAIL_BIAS(t->reg[tDetail].u) << 2) << 6;
01088         t->detailscale = TEXDETAIL_DETAIL_SCALE(t->reg[tDetail].u);
01089 
01090         /* no longer dirty */
01091         t->regdirty = false;
01092 
01093         /* check for separate RGBA filtering */
01094         if (TEXDETAIL_SEPARATE_RGBA_FILTER(t->reg[tDetail].u))
01095                 E_Exit("Separate RGBA filters!");
01096 }
01097 
01098 
01099 INLINE INT32 prepare_tmu(tmu_state *t)
01100 {
01101         INT64 texdx, texdy;
01102         INT32 lodbase;
01103 
01104         /* if the texture parameters are dirty, update them */
01105         if (t->regdirty)
01106         {
01107                 recompute_texture_params(t);
01108 
01109                 /* ensure that the NCC tables are up to date */
01110                 if ((TEXMODE_FORMAT(t->reg[textureMode].u) & 7) == 1)
01111                 {
01112                         ncc_table *n = &t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)];
01113                         t->texel[1] = t->texel[9] = n->texel;
01114                         if (n->dirty)
01115                                 ncc_table_update(n);
01116                 }
01117         }
01118 
01119         /* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */
01120         texdx = (INT64)(t->dsdx >> 14) * (INT64)(t->dsdx >> 14) + (INT64)(t->dtdx >> 14) * (INT64)(t->dtdx >> 14);
01121         texdy = (INT64)(t->dsdy >> 14) * (INT64)(t->dsdy >> 14) + (INT64)(t->dtdy >> 14) * (INT64)(t->dtdy >> 14);
01122 
01123         /* pick whichever is larger and shift off some high bits -> 28.20 */
01124         if (texdx < texdy)
01125                 texdx = texdy;
01126         texdx >>= 16;
01127 
01128         /* use our fast reciprocal/log on this value; it expects input as a */
01129         /* 16.32 number, and returns the log of the reciprocal, so we have to */
01130         /* adjust the result: negative to get the log of the original value */
01131         /* plus 12 to account for the extra exponent, and divided by 2 to */
01132         /* get the log of the square root of texdx */
01133         (void)fast_reciplog(texdx, &lodbase);
01134         return (-lodbase + (12 << 8)) / 2;
01135 }
01136 
01137 
01138 INLINE INT32 round_coordinate(float value)
01139 {
01140         INT32 result = (INT32)floor(value);
01141         return result + (value - (float)result > 0.5f);
01142 }
01143 
01144 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)
01145 {
01146         float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3;
01147         const poly_vertex *tv;
01148         INT32 curscan, scaninc=1;
01149 
01150         INT32 v1yclip, v3yclip;
01151         INT32 v1y, v3y;//, v1x;
01152 
01153         /* first sort by Y */
01154         if (v2->y < v1->y)
01155         {
01156                 tv = v1;
01157                 v1 = v2;
01158                 v2 = tv;
01159         }
01160         if (v3->y < v2->y)
01161         {
01162                 tv = v2;
01163                 v2 = v3;
01164                 v3 = tv;
01165                 if (v2->y < v1->y)
01166                 {
01167                         tv = v1;
01168                         v1 = v2;
01169                         v2 = tv;
01170                 }
01171         }
01172 
01173         /* compute some integral X/Y vertex values */
01174 //      v1x = round_coordinate(v1->x);
01175         v1y = round_coordinate(v1->y);
01176         v3y = round_coordinate(v3->y);
01177 
01178         /* clip coordinates */
01179         v1yclip = v1y;
01180         v3yclip = v3y;// + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
01181         if (v3yclip - v1yclip <= 0)
01182                 return;
01183 
01184         /* compute the slopes for each portion of the triangle */
01185         dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y);
01186         dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y);
01187         dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y);
01188 
01189         poly_extent *extent = new poly_extent;
01190         int extnum=0;
01191         for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
01192         {
01193                 {
01194                         float fully = (float)(curscan + extnum) + 0.5f;
01195                         float startx = v1->x + (fully - v1->y) * dxdy_v1v3;
01196                         float stopx;
01197                         INT32 istartx, istopx;
01198 
01199                         /* compute the ending X based on which part of the triangle we're in */
01200                         if (fully < v2->y)
01201                                 stopx = v1->x + (fully - v1->y) * dxdy_v1v2;
01202                         else
01203                                 stopx = v2->x + (fully - v2->y) * dxdy_v2v3;
01204 
01205                         /* clamp to full pixels */
01206                         istartx = round_coordinate(startx);
01207                         istopx = round_coordinate(stopx);
01208 
01209                         /* force start < stop */
01210                         if (istartx > istopx)
01211                         {
01212                                 INT32 temp = istartx;
01213                                 istartx = istopx;
01214                                 istopx = temp;
01215                         }
01216 
01217                         /* set the extent and update the total pixel count */
01218                         if (istartx >= istopx)
01219                                 istartx = istopx = 0;
01220 
01221                         extent->startx = istartx;
01222                         extent->stopx = istopx;
01223                         (callback)(dest,curscan,extent,extra);
01224                 }
01225         }
01226 
01227         delete extent;
01228 }
01229 
01230 
01231 
01232 void poly_render_triangle_custom(void *dest, int startscanline, int numscanlines, const poly_extent *extents, poly_extra_data *extra)
01233 {
01234         INT32 curscan, scaninc;
01235         INT32 v1yclip, v3yclip;
01236 
01237         v1yclip = startscanline;
01238         v3yclip = startscanline + numscanlines;
01239 
01240         if (v3yclip - v1yclip <= 0)
01241                 return;
01242 
01243         for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
01244         {
01245                 tri_work_unit *unit = new tri_work_unit;
01246                 int extnum=0;
01247 
01248                 /* determine how much to advance to hit the next bucket */
01249                 scaninc = 1;
01250 
01251                 {
01252                         const poly_extent *extent = &extents[(curscan + extnum) - startscanline];
01253                         INT32 istartx = extent->startx, istopx = extent->stopx;
01254 
01255                         /* force start < stop */
01256                         if (istartx > istopx)
01257                         {
01258                                 INT32 temp = istartx;
01259                                 istartx = istopx;
01260                                 istopx = temp;
01261                         }
01262 
01263                         /* set the extent and update the total pixel count */
01264                         unit->extent[extnum].startx = (INT16)istartx;
01265                         unit->extent[extnum].stopx = (INT16)istopx;
01266                         raster_fastfill(dest,curscan,extent,extra);
01267                 }
01268                 delete unit;
01269         }
01270 }
01271 
01272 
01273 
01274 /*************************************
01275  *
01276  *  Statistics management
01277  *
01278  *************************************/
01279 
01280 static void accumulate_statistics(voodoo_state *v, const stats_block *stats)
01281 {
01282         /* apply internal voodoo statistics */
01283         v->reg[fbiPixelsIn].u += (UINT32)stats->pixels_in;
01284         v->reg[fbiPixelsOut].u += (UINT32)stats->pixels_out;
01285         v->reg[fbiChromaFail].u += (UINT32)stats->chroma_fail;
01286         v->reg[fbiZfuncFail].u += (UINT32)stats->zfunc_fail;
01287         v->reg[fbiAfuncFail].u += (UINT32)stats->afunc_fail;
01288 }
01289 
01290 static void update_statistics(voodoo_state *v, bool accumulate)
01291 {
01292         /* accumulate/reset statistics from all units */
01293         if (accumulate)
01294                 accumulate_statistics(v, &v->thread_stats[0]);
01295         memset(&v->thread_stats[0], 0, sizeof(v->thread_stats[0]));
01296 
01297         /* accumulate/reset statistics from the LFB */
01298         if (accumulate)
01299                 accumulate_statistics(v, &v->fbi.lfb_stats);
01300         memset(&v->fbi.lfb_stats, 0, sizeof(v->fbi.lfb_stats));
01301 }
01302 
01303 
01304 
01305 /*************************************
01306  *
01307  *  Voodoo register writes
01308  *
01309  *************************************/
01310 
01311 void register_w(UINT32 offset, UINT32 data) {
01312 //      voodoo_reg reg;
01313         UINT32 regnum  = (offset) & 0xff;
01314         UINT32 chips   = (offset>>8) & 0xf;
01315 //      reg.u = data;
01316 
01317         INT64 data64;
01318 
01319 //      LOG(LOG_VOODOO,LOG_WARN)("V3D:WR chip %x reg %x value %08x(%s)", chips, regnum<<2, data, voodoo_reg_name[regnum]);
01320 
01321         if (chips == 0)
01322                 chips = 0xf;
01323         chips &= v->chipmask;
01324 
01325         /* the first 64 registers can be aliased differently */
01326         if ((offset & 0x800c0) == 0x80000 && v->alt_regmap)
01327                 regnum = register_alias_map[offset & 0x3f];
01328         else
01329                 regnum = offset & 0xff;
01330 
01331         /* first make sure this register is readable */
01332         if (!(v->regaccess[regnum] & REGISTER_WRITE))
01333         {
01334                 if (regnum <= 0xe0) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.ERROR:Invalid attempt to write %s\n", v->regnames[regnum]);
01335                 else LOG(LOG_VOODOO,LOG_WARN)("VOODOO.ERROR:Invalid attempt to write #%x\n", regnum);
01336                 return;
01337         }
01338 
01339         /* switch off the register */
01340         switch (regnum)
01341         {
01342                 /* Vertex data is 12.4 formatted fixed point */
01343                 case fvertexAx:
01344                         data = (UINT32)float_to_int32(data, 4);
01345                 case vertexAx:
01346                         if (chips & 1) v->fbi.ax = (INT16)(data&0xffff);
01347                         break;
01348 
01349                 case fvertexAy:
01350                         data = (UINT32)float_to_int32(data, 4);
01351                 case vertexAy:
01352                         if (chips & 1) v->fbi.ay = (INT16)(data&0xffff);
01353                         break;
01354 
01355                 case fvertexBx:
01356                         data = (UINT32)float_to_int32(data, 4);
01357                 case vertexBx:
01358                         if (chips & 1) v->fbi.bx = (INT16)(data&0xffff);
01359                         break;
01360 
01361                 case fvertexBy:
01362                         data = (UINT32)float_to_int32(data, 4);
01363                 case vertexBy:
01364                         if (chips & 1) v->fbi.by = (INT16)(data&0xffff);
01365                         break;
01366 
01367                 case fvertexCx:
01368                         data = (UINT32)float_to_int32(data, 4);
01369                 case vertexCx:
01370                         if (chips & 1) v->fbi.cx = (INT16)(data&0xffff);
01371                         break;
01372 
01373                 case fvertexCy:
01374                         data = (UINT32)float_to_int32(data, 4);
01375                 case vertexCy:
01376                         if (chips & 1) v->fbi.cy = (INT16)(data&0xffff);
01377                         break;
01378 
01379                 /* RGB data is 12.12 formatted fixed point */
01380                 case fstartR:
01381                         data = (UINT32)float_to_int32(data, 12);
01382                 case startR:
01383                         if (chips & 1) v->fbi.startr = (INT32)(data << 8) >> 8;
01384                         break;
01385 
01386                 case fstartG:
01387                         data = (UINT32)float_to_int32(data, 12);
01388                 case startG:
01389                         if (chips & 1) v->fbi.startg = (INT32)(data << 8) >> 8;
01390                         break;
01391 
01392                 case fstartB:
01393                         data = (UINT32)float_to_int32(data, 12);
01394                 case startB:
01395                         if (chips & 1) v->fbi.startb = (INT32)(data << 8) >> 8;
01396                         break;
01397 
01398                 case fstartA:
01399                         data = (UINT32)float_to_int32(data, 12);
01400                 case startA:
01401                         if (chips & 1) v->fbi.starta = (INT32)(data << 8) >> 8;
01402                         break;
01403 
01404                 case fdRdX:
01405                         data = (UINT32)float_to_int32(data, 12);
01406                 case dRdX:
01407                         if (chips & 1) v->fbi.drdx = (INT32)(data << 8) >> 8;
01408                         break;
01409 
01410                 case fdGdX:
01411                         data = (UINT32)float_to_int32(data, 12);
01412                 case dGdX:
01413                         if (chips & 1) v->fbi.dgdx = (INT32)(data << 8) >> 8;
01414                         break;
01415 
01416                 case fdBdX:
01417                         data = (UINT32)float_to_int32(data, 12);
01418                 case dBdX:
01419                         if (chips & 1) v->fbi.dbdx = (INT32)(data << 8) >> 8;
01420                         break;
01421 
01422                 case fdAdX:
01423                         data = (UINT32)float_to_int32(data, 12);
01424                 case dAdX:
01425                         if (chips & 1) v->fbi.dadx = (INT32)(data << 8) >> 8;
01426                         break;
01427 
01428                 case fdRdY:
01429                         data = (UINT32)float_to_int32(data, 12);
01430                 case dRdY:
01431                         if (chips & 1) v->fbi.drdy = (INT32)(data << 8) >> 8;
01432                         break;
01433 
01434                 case fdGdY:
01435                         data = (UINT32)float_to_int32(data, 12);
01436                 case dGdY:
01437                         if (chips & 1) v->fbi.dgdy = (INT32)(data << 8) >> 8;
01438                         break;
01439 
01440                 case fdBdY:
01441                         data = (UINT32)float_to_int32(data, 12);
01442                 case dBdY:
01443                         if (chips & 1) v->fbi.dbdy = (INT32)(data << 8) >> 8;
01444                         break;
01445 
01446                 case fdAdY:
01447                         data = (UINT32)float_to_int32(data, 12);
01448                 case dAdY:
01449                         if (chips & 1) v->fbi.dady = (INT32)(data << 8) >> 8;
01450                         break;
01451 
01452                 /* Z data is 20.12 formatted fixed point */
01453                 case fstartZ:
01454                         data = (UINT32)float_to_int32(data, 12);
01455                 case startZ:
01456                         if (chips & 1) v->fbi.startz = (INT32)data;
01457                         break;
01458 
01459                 case fdZdX:
01460                         data = (UINT32)float_to_int32(data, 12);
01461                 case dZdX:
01462                         if (chips & 1) v->fbi.dzdx = (INT32)data;
01463                         break;
01464 
01465                 case fdZdY:
01466                         data = (UINT32)float_to_int32(data, 12);
01467                 case dZdY:
01468                         if (chips & 1) v->fbi.dzdy = (INT32)data;
01469                         break;
01470 
01471                 /* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */
01472                 case fstartS:
01473                         data64 = float_to_int64(data, 32);
01474                         if (chips & 2) v->tmu[0].starts = data64;
01475                         if (chips & 4) v->tmu[1].starts = data64;
01476                         break;
01477                 case startS:
01478                         if (chips & 2) v->tmu[0].starts = (INT64)(INT32)data << 14;
01479                         if (chips & 4) v->tmu[1].starts = (INT64)(INT32)data << 14;
01480                         break;
01481 
01482                 case fstartT:
01483                         data64 = float_to_int64(data, 32);
01484                         if (chips & 2) v->tmu[0].startt = data64;
01485                         if (chips & 4) v->tmu[1].startt = data64;
01486                         break;
01487                 case startT:
01488                         if (chips & 2) v->tmu[0].startt = (INT64)(INT32)data << 14;
01489                         if (chips & 4) v->tmu[1].startt = (INT64)(INT32)data << 14;
01490                         break;
01491 
01492                 case fdSdX:
01493                         data64 = float_to_int64(data, 32);
01494                         if (chips & 2) v->tmu[0].dsdx = data64;
01495                         if (chips & 4) v->tmu[1].dsdx = data64;
01496                         break;
01497                 case dSdX:
01498                         if (chips & 2) v->tmu[0].dsdx = (INT64)(INT32)data << 14;
01499                         if (chips & 4) v->tmu[1].dsdx = (INT64)(INT32)data << 14;
01500                         break;
01501 
01502                 case fdTdX:
01503                         data64 = float_to_int64(data, 32);
01504                         if (chips & 2) v->tmu[0].dtdx = data64;
01505                         if (chips & 4) v->tmu[1].dtdx = data64;
01506                         break;
01507                 case dTdX:
01508                         if (chips & 2) v->tmu[0].dtdx = (INT64)(INT32)data << 14;
01509                         if (chips & 4) v->tmu[1].dtdx = (INT64)(INT32)data << 14;
01510                         break;
01511 
01512                 case fdSdY:
01513                         data64 = float_to_int64(data, 32);
01514                         if (chips & 2) v->tmu[0].dsdy = data64;
01515                         if (chips & 4) v->tmu[1].dsdy = data64;
01516                         break;
01517                 case dSdY:
01518                         if (chips & 2) v->tmu[0].dsdy = (INT64)(INT32)data << 14;
01519                         if (chips & 4) v->tmu[1].dsdy = (INT64)(INT32)data << 14;
01520                         break;
01521 
01522                 case fdTdY:
01523                         data64 = float_to_int64(data, 32);
01524                         if (chips & 2) v->tmu[0].dtdy = data64;
01525                         if (chips & 4) v->tmu[1].dtdy = data64;
01526                         break;
01527                 case dTdY:
01528                         if (chips & 2) v->tmu[0].dtdy = (INT64)(INT32)data << 14;
01529                         if (chips & 4) v->tmu[1].dtdy = (INT64)(INT32)data << 14;
01530                         break;
01531 
01532                 /* W data is 2.30 formatted fixed point, converted to 16.32 internally */
01533                 case fstartW:
01534                         data64 = float_to_int64(data, 32);
01535                         if (chips & 1) v->fbi.startw = data64;
01536                         if (chips & 2) v->tmu[0].startw = data64;
01537                         if (chips & 4) v->tmu[1].startw = data64;
01538                         break;
01539                 case startW:
01540                         if (chips & 1) v->fbi.startw = (INT64)(INT32)data << 2;
01541                         if (chips & 2) v->tmu[0].startw = (INT64)(INT32)data << 2;
01542                         if (chips & 4) v->tmu[1].startw = (INT64)(INT32)data << 2;
01543                         break;
01544 
01545                 case fdWdX:
01546                         data64 = float_to_int64(data, 32);
01547                         if (chips & 1) v->fbi.dwdx = data64;
01548                         if (chips & 2) v->tmu[0].dwdx = data64;
01549                         if (chips & 4) v->tmu[1].dwdx = data64;
01550                         break;
01551                 case dWdX:
01552                         if (chips & 1) v->fbi.dwdx = (INT64)(INT32)data << 2;
01553                         if (chips & 2) v->tmu[0].dwdx = (INT64)(INT32)data << 2;
01554                         if (chips & 4) v->tmu[1].dwdx = (INT64)(INT32)data << 2;
01555                         break;
01556 
01557                 case fdWdY:
01558                         data64 = float_to_int64(data, 32);
01559                         if (chips & 1) v->fbi.dwdy = data64;
01560                         if (chips & 2) v->tmu[0].dwdy = data64;
01561                         if (chips & 4) v->tmu[1].dwdy = data64;
01562                         break;
01563                 case dWdY:
01564                         if (chips & 1) v->fbi.dwdy = (INT64)(INT32)data << 2;
01565                         if (chips & 2) v->tmu[0].dwdy = (INT64)(INT32)data << 2;
01566                         if (chips & 4) v->tmu[1].dwdy = (INT64)(INT32)data << 2;
01567                         break;
01568 
01569                 /* setup bits */
01570                 case sARGB:
01571                         if (chips & 1)
01572                         {
01573                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01574                                 v->reg[sAlpha].f = (float)RGB_ALPHA(data);
01575                                 v->reg[sRed].f = (float)RGB_RED(data);
01576                                 v->reg[sGreen].f = (float)RGB_GREEN(data);
01577                                 v->reg[sBlue].f = (float)RGB_BLUE(data);
01578                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01579                         }
01580                         break;
01581 
01582                 /* mask off invalid bits for different cards */
01583                 case fbzColorPath:
01584                         if (v->type < VOODOO_2)
01585                                 data &= 0x0fffffff;
01586                         if (chips & 1) v->reg[fbzColorPath].u = data;
01587                         break;
01588 
01589                 case fbzMode:
01590                         if (v->type < VOODOO_2)
01591                                 data &= 0x001fffff;
01592                         if (chips & 1) {
01593                                 if (v->ogl && v->active && (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u)!=FBZMODE_Y_ORIGIN(data))) {
01594                                         v->reg[fbzMode].u = data;
01595                                         CPU_Core_Dyn_X86_SaveDHFPUState();
01596                                         voodoo_ogl_set_window(v);
01597                                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01598                                 } else {
01599                                         v->reg[fbzMode].u = data;
01600                                 }
01601                         }
01602                         break;
01603 
01604                 case fogMode:
01605                         if (v->type < VOODOO_2)
01606                                 data &= 0x0000003f;
01607                         if (chips & 1) v->reg[fogMode].u = data;
01608                         break;
01609 
01610                 /* triangle drawing */
01611                 case triangleCMD:
01612                         CPU_Core_Dyn_X86_SaveDHFPUState();
01613                         triangle(v);
01614                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01615                         break;
01616 
01617                 case ftriangleCMD:
01618                         CPU_Core_Dyn_X86_SaveDHFPUState();
01619                         triangle(v);
01620                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01621                         break;
01622 
01623                 case sBeginTriCMD:
01624 //                      E_Exit("begin tri");
01625                         CPU_Core_Dyn_X86_SaveDHFPUState();
01626                         begin_triangle(v);
01627                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01628                         break;
01629 
01630                 case sDrawTriCMD:
01631 //                      E_Exit("draw tri");
01632                         CPU_Core_Dyn_X86_SaveDHFPUState();
01633                         draw_triangle(v);
01634                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01635                         break;
01636 
01637                 /* other commands */
01638                 case nopCMD:
01639                         if (data & 1)
01640                                 reset_counters(v);
01641                         if (data & 2)
01642                                 v->reg[fbiTrianglesOut].u = 0;
01643                         break;
01644 
01645                 case fastfillCMD:
01646                         CPU_Core_Dyn_X86_SaveDHFPUState();
01647                         fastfill(v);
01648                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01649                         break;
01650 
01651                 case swapbufferCMD:
01652 //                      CPU_Core_Dyn_X86_SaveDHFPUState();
01653                         swapbuffer(v, data);
01654 //                      CPU_Core_Dyn_X86_RestoreDHFPUState();
01655                         break;
01656 
01657                 /* gamma table access -- Voodoo/Voodoo2 only */
01658                 case clutData:
01659 /*                      if (chips & 1)
01660                         {
01661                                 if (!FBIINIT1_VIDEO_TIMING_RESET(v->reg[fbiInit1].u))
01662                                 {
01663                                         int index = data >> 24;
01664                                         if (index <= 32)
01665                                         {
01666 //                                              v->fbi.clut[index] = data;
01667                                         }
01668                                 }
01669                                 else
01670                                         LOG(LOG_VOODOO,LOG_WARN)("clutData ignored because video timing reset = 1\n");
01671                         } */
01672                         break;
01673 
01674                 /* external DAC access -- Voodoo/Voodoo2 only */
01675                 case dacData:
01676                         if (chips & 1)
01677                         {
01678                                 if (!(data & 0x800))
01679                                         dacdata_w(&v->dac, (data >> 8) & 7, data & 0xff);
01680                                 else
01681                                         dacdata_r(&v->dac, (data >> 8) & 7);
01682                         }
01683                         break;
01684 
01685                 /* vertical sync rate -- Voodoo/Voodoo2 only */
01686                 case hSync:
01687                 case vSync:
01688                 case backPorch:
01689                 case videoDimensions:
01690                         if (chips & 1)
01691                         {
01692                                 v->reg[regnum].u = data;
01693                                 if (v->reg[hSync].u != 0 && v->reg[vSync].u != 0 && v->reg[videoDimensions].u != 0)
01694                                 {
01695                                         CPU_Core_Dyn_X86_SaveDHFPUState();
01696                                         int htotal = (int)(((v->reg[hSync].u >> 16) & 0x3ff) + 1u + (v->reg[hSync].u & 0xff) + 1u);
01697                                         int vtotal = (int)(((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff));
01698                                         int hvis = v->reg[videoDimensions].u & 0x3ff;
01699                                         int vvis = (v->reg[videoDimensions].u >> 16) & 0x3ff;
01700                                         int hbp = (int)((v->reg[backPorch].u & 0xff) + 2u);
01701                                         int vbp = (int)((v->reg[backPorch].u >> 16) & 0xff);
01702 //                                      attoseconds_t refresh = video_screen_get_frame_period(v->screen).attoseconds;
01703                                         attoseconds_t refresh = 0;
01704                                         attoseconds_t stdperiod, medperiod, vgaperiod;
01705                                         attoseconds_t stddiff, meddiff, vgadiff;
01706                                         rectangle visarea;
01707 
01708                                         /* create a new visarea */
01709                                         visarea.min_x = hbp;
01710                                         visarea.max_x = hbp + hvis - 1;
01711                                         visarea.min_y = vbp;
01712                                         visarea.max_y = vbp + vvis - 1;
01713 
01714                                         /* keep within bounds */
01715                                         visarea.max_x = MIN(visarea.max_x, htotal - 1);
01716                                         visarea.max_y = MIN(visarea.max_y, vtotal - 1);
01717 
01718                                         /* compute the new period for standard res, medium res, and VGA res */
01719                                         stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal;
01720                                         medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal;
01721                                         vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal;
01722 
01723                                         /* compute a diff against the current refresh period */
01724                                         stddiff = stdperiod - refresh;
01725                                         if (stddiff < 0) stddiff = -stddiff;
01726                                         meddiff = medperiod - refresh;
01727                                         if (meddiff < 0) meddiff = -meddiff;
01728                                         vgadiff = vgaperiod - refresh;
01729                                         if (vgadiff < 0) vgadiff = -vgadiff;
01730 
01731                                         LOG(LOG_VOODOO,LOG_WARN)("hSync=%08X  vSync=%08X  backPorch=%08X  videoDimensions=%08X\n",
01732                                                 v->reg[hSync].u, v->reg[vSync].u, v->reg[backPorch].u, v->reg[videoDimensions].u);
01733                                         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);
01734 
01735                                         /* configure the screen based on which one matches the closest */
01736                                         if (stddiff < meddiff && stddiff < vgadiff)
01737                                         {
01738 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, stdperiod);
01739                                                 LOG(LOG_VOODOO,LOG_WARN)("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod));
01740                                         }
01741                                         else if (meddiff < vgadiff)
01742                                         {
01743 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, medperiod);
01744                                                 LOG(LOG_VOODOO,LOG_WARN)("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod));
01745                                         }
01746                                         else
01747                                         {
01748 //                                              video_screen_configure(v->screen, htotal, vtotal, &visarea, vgaperiod);
01749                                                 LOG(LOG_VOODOO,LOG_WARN)("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod));
01750                                         }
01751 
01752                                         /* configure the new framebuffer info */
01753                                         UINT32 new_width = ((UINT32)hvis+1u) & ~1u;
01754                                         UINT32 new_height = ((UINT32)vvis+1u) & ~1u;
01755                                         if ((v->fbi.width != new_width) || (v->fbi.height != new_height)) {
01756                                                 v->fbi.width = new_width;
01757                                                 v->fbi.height = new_height;
01758                                                 v->ogl_dimchange = true;
01759                                         }
01760 //                                      v->fbi.xoffs = hbp;
01761 //                                      v->fbi.yoffs = vbp;
01762 //                                      v->fbi.vsyncscan = (v->reg[vSync].u >> 16) & 0xfff;
01763 
01764                                         /* recompute the time of VBLANK */
01765 //                                      adjust_vblank_timer(v);
01766 
01767                                         /* if changing dimensions, update video memory layout */
01768                                         if (regnum == videoDimensions)
01769                                                 recompute_video_memory(v);
01770 
01771                                         Voodoo_UpdateScreenStart();
01772                                         CPU_Core_Dyn_X86_RestoreDHFPUState();
01773                                 }
01774                         }
01775                         break;
01776 
01777                 /* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
01778                 case fbiInit0:
01779                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01780                         {
01781                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01782                                 Voodoo_Output_Enable(FBIINIT0_VGA_PASSTHRU(data));
01783                                 v->reg[fbiInit0].u = data;
01784                                 if (FBIINIT0_GRAPHICS_RESET(data))
01785                                         soft_reset(v);
01786                                 recompute_video_memory(v);
01787                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01788                         }
01789                         break;
01790 
01791                 /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */
01792                 case fbiInit5:
01793                 case fbiInit6:
01794                         if (v->type < VOODOO_2)
01795                                 break;
01796                         /* else fall through... */
01797 
01798                 /* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */
01799                 /* most of these affect memory layout, so always recompute that when done */
01800                 case fbiInit1:
01801                 case fbiInit2:
01802                 case fbiInit4:
01803                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01804                         {
01805                                 v->reg[regnum].u = data;
01806                                 recompute_video_memory(v);
01807                         }
01808                         break;
01809 
01810                 case fbiInit3:
01811                         if ((chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable))
01812                         {
01813                                 v->reg[regnum].u = data;
01814                                 v->alt_regmap = (FBIINIT3_TRI_REGISTER_REMAP(data) > 0);
01815                                 v->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(v->reg[fbiInit3].u);
01816                                 recompute_video_memory(v);
01817                         }
01818                         break;
01819 
01820                 /* nccTable entries are processed and expanded immediately */
01821                 case nccTable+0:
01822                 case nccTable+1:
01823                 case nccTable+2:
01824                 case nccTable+3:
01825                 case nccTable+4:
01826                 case nccTable+5:
01827                 case nccTable+6:
01828                 case nccTable+7:
01829                 case nccTable+8:
01830                 case nccTable+9:
01831                 case nccTable+10:
01832                 case nccTable+11:
01833                         if (chips & 2) ncc_table_write(&v->tmu[0].ncc[0], regnum - nccTable, data);
01834                         if (chips & 4) ncc_table_write(&v->tmu[1].ncc[0], regnum - nccTable, data);
01835                         break;
01836 
01837                 case nccTable+12:
01838                 case nccTable+13:
01839                 case nccTable+14:
01840                 case nccTable+15:
01841                 case nccTable+16:
01842                 case nccTable+17:
01843                 case nccTable+18:
01844                 case nccTable+19:
01845                 case nccTable+20:
01846                 case nccTable+21:
01847                 case nccTable+22:
01848                 case nccTable+23:
01849                         if (chips & 2) ncc_table_write(&v->tmu[0].ncc[1], regnum - (nccTable+12), data);
01850                         if (chips & 4) ncc_table_write(&v->tmu[1].ncc[1], regnum - (nccTable+12), data);
01851                         break;
01852 
01853                 /* fogTable entries are processed and expanded immediately */
01854                 case fogTable+0:
01855                 case fogTable+1:
01856                 case fogTable+2:
01857                 case fogTable+3:
01858                 case fogTable+4:
01859                 case fogTable+5:
01860                 case fogTable+6:
01861                 case fogTable+7:
01862                 case fogTable+8:
01863                 case fogTable+9:
01864                 case fogTable+10:
01865                 case fogTable+11:
01866                 case fogTable+12:
01867                 case fogTable+13:
01868                 case fogTable+14:
01869                 case fogTable+15:
01870                 case fogTable+16:
01871                 case fogTable+17:
01872                 case fogTable+18:
01873                 case fogTable+19:
01874                 case fogTable+20:
01875                 case fogTable+21:
01876                 case fogTable+22:
01877                 case fogTable+23:
01878                 case fogTable+24:
01879                 case fogTable+25:
01880                 case fogTable+26:
01881                 case fogTable+27:
01882                 case fogTable+28:
01883                 case fogTable+29:
01884                 case fogTable+30:
01885                 case fogTable+31:
01886                         if (chips & 1)
01887                         {
01888                                 int base = 2 * (int)(regnum - fogTable);
01889                                 v->fbi.fogdelta[base + 0] = (data >> 0) & 0xff;
01890                                 v->fbi.fogblend[base + 0] = (data >> 8) & 0xff;
01891                                 v->fbi.fogdelta[base + 1] = (data >> 16) & 0xff;
01892                                 v->fbi.fogblend[base + 1] = (data >> 24) & 0xff;
01893                         }
01894                         break;
01895 
01896                 /* texture modifications cause us to recompute everything */
01897                 case textureMode:
01898                 case tLOD:
01899                 case tDetail:
01900                 case texBaseAddr:
01901                 case texBaseAddr_1:
01902                 case texBaseAddr_2:
01903                 case texBaseAddr_3_8:
01904                         if (chips & 2)
01905                         {
01906                                 v->tmu[0].reg[regnum].u = data;
01907                                 v->tmu[0].regdirty = true;
01908                         }
01909                         if (chips & 4)
01910                         {
01911                                 v->tmu[1].reg[regnum].u = data;
01912                                 v->tmu[1].regdirty = true;
01913                         }
01914                         break;
01915 
01916                 case trexInit1:
01917                         /* send tmu config data to the frame buffer */
01918                         v->send_config = (TREXINIT_SEND_TMU_CONFIG(data) > 0);
01919                         goto default_case;
01920                         break;
01921 
01922                 case clipLowYHighY:
01923                 case clipLeftRight:
01924                         if (chips & 1) v->reg[0x000 + regnum].u = data;
01925                         if (v->ogl) {
01926                                 CPU_Core_Dyn_X86_SaveDHFPUState();
01927                                 voodoo_ogl_clip_window(v);
01928                                 CPU_Core_Dyn_X86_RestoreDHFPUState();
01929                         }
01930                         break;
01931 
01932                 /* these registers are referenced in the renderer; we must wait for pending work before changing */
01933                 case chromaRange:
01934                 case chromaKey:
01935                 case alphaMode:
01936                 case fogColor:
01937                 case stipple:
01938                 case zaColor:
01939                 case color1:
01940                 case color0:
01941                         /* fall through to default implementation */
01942 
01943                 /* by default, just feed the data to the chips */
01944                 default:
01945 default_case:
01946                         if (chips & 1) v->reg[0x000 + regnum].u = data;
01947                         if (chips & 2) v->reg[0x100 + regnum].u = data;
01948                         if (chips & 4) v->reg[0x200 + regnum].u = data;
01949                         if (chips & 8) v->reg[0x300 + regnum].u = data;
01950                         break;
01951         }
01952 
01953 }
01954 
01955 
01956 
01957 /*************************************
01958  *
01959  *  Voodoo LFB writes
01960  *
01961  *************************************/
01962 
01963 void lfb_w(UINT32 offset, UINT32 data, UINT32 mem_mask) {
01964         LOG(LOG_VOODOO,LOG_WARN)("V3D:WR LFB offset %X value %08X", offset, data);
01965         UINT16 *dest, *depth;
01966         UINT32 destmax, depthmax;
01967 
01968         int sr[2], sg[2], sb[2], sa[2], sw[2];
01969         int x, y, scry, mask;
01970         int pix, destbuf;
01971 
01972         /* byte swizzling */
01973         if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u))
01974         {
01975                 data = FLIPENDIAN_INT32(data);
01976                 mem_mask = FLIPENDIAN_INT32(mem_mask);
01977         }
01978 
01979         /* word swapping */
01980         if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u))
01981         {
01982                 data = (data << 16) | (data >> 16);
01983                 mem_mask = (mem_mask << 16) | (mem_mask >> 16);
01984         }
01985 
01986         /* extract default depth and alpha values */
01987         sw[0] = sw[1] = (int)(v->reg[zaColor].u & 0xffff);
01988         sa[0] = sa[1] = (int)(v->reg[zaColor].u >> 24);
01989 
01990         /* first extract A,R,G,B from the data */
01991         switch (LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(v->reg[lfbMode].u))
01992         {
01993                 case 16*0 + 0:          /* ARGB, 16-bit RGB 5-6-5 */
01994                 case 16*2 + 0:          /* RGBA, 16-bit RGB 5-6-5 */
01995                         EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
01996                         EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]);
01997                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
01998                         offset <<= 1;
01999                         break;
02000                 case 16*1 + 0:          /* ABGR, 16-bit RGB 5-6-5 */
02001                 case 16*3 + 0:          /* BGRA, 16-bit RGB 5-6-5 */
02002                         EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
02003                         EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02004                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02005                         offset <<= 1;
02006                         break;
02007 
02008                 case 16*0 + 1:          /* ARGB, 16-bit RGB x-5-5-5 */
02009                         EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
02010                         EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]);
02011                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02012                         offset <<= 1;
02013                         break;
02014                 case 16*1 + 1:          /* ABGR, 16-bit RGB x-5-5-5 */
02015                         EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
02016                         EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02017                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02018                         offset <<= 1;
02019                         break;
02020                 case 16*2 + 1:          /* RGBA, 16-bit RGB x-5-5-5 */
02021                         EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
02022                         EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]);
02023                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02024                         offset <<= 1;
02025                         break;
02026                 case 16*3 + 1:          /* BGRA, 16-bit RGB x-5-5-5 */
02027                         EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
02028                         EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]);
02029                         mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4);
02030                         offset <<= 1;
02031                         break;
02032 
02033                 case 16*0 + 2:          /* ARGB, 16-bit ARGB 1-5-5-5 */
02034                         EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02035                         EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]);
02036                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02037                         offset <<= 1;
02038                         break;
02039                 case 16*1 + 2:          /* ABGR, 16-bit ARGB 1-5-5-5 */
02040                         EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02041                         EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]);
02042                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02043                         offset <<= 1;
02044                         break;
02045                 case 16*2 + 2:          /* RGBA, 16-bit ARGB 1-5-5-5 */
02046                         EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02047                         EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]);
02048                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02049                         offset <<= 1;
02050                         break;
02051                 case 16*3 + 2:          /* BGRA, 16-bit ARGB 1-5-5-5 */
02052                         EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02053                         EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]);
02054                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4);
02055                         offset <<= 1;
02056                         break;
02057 
02058                 case 16*0 + 4:          /* ARGB, 32-bit RGB x-8-8-8 */
02059                         EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]);
02060                         mask = LFB_RGB_PRESENT;
02061                         break;
02062                 case 16*1 + 4:          /* ABGR, 32-bit RGB x-8-8-8 */
02063                         EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]);
02064                         mask = LFB_RGB_PRESENT;
02065                         break;
02066                 case 16*2 + 4:          /* RGBA, 32-bit RGB x-8-8-8 */
02067                         EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]);
02068                         mask = LFB_RGB_PRESENT;
02069                         break;
02070                 case 16*3 + 4:          /* BGRA, 32-bit RGB x-8-8-8 */
02071                         EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]);
02072                         mask = LFB_RGB_PRESENT;
02073                         break;
02074 
02075                 case 16*0 + 5:          /* ARGB, 32-bit ARGB 8-8-8-8 */
02076                         EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02077                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02078                         break;
02079                 case 16*1 + 5:          /* ABGR, 32-bit ARGB 8-8-8-8 */
02080                         EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02081                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02082                         break;
02083                 case 16*2 + 5:          /* RGBA, 32-bit ARGB 8-8-8-8 */
02084                         EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02085                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02086                         break;
02087                 case 16*3 + 5:          /* BGRA, 32-bit ARGB 8-8-8-8 */
02088                         EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02089                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT;
02090                         break;
02091 
02092                 case 16*0 + 12:         /* ARGB, 32-bit depth+RGB 5-6-5 */
02093                 case 16*2 + 12:         /* RGBA, 32-bit depth+RGB 5-6-5 */
02094                         sw[0] = (int)(data >> 16);
02095                         EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]);
02096                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02097                         break;
02098                 case 16*1 + 12:         /* ABGR, 32-bit depth+RGB 5-6-5 */
02099                 case 16*3 + 12:         /* BGRA, 32-bit depth+RGB 5-6-5 */
02100                         sw[0] = (int)(data >> 16);
02101                         EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]);
02102                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02103                         break;
02104 
02105                 case 16*0 + 13:         /* ARGB, 32-bit depth+RGB x-5-5-5 */
02106                         sw[0] = (int)(data >> 16);
02107                         EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]);
02108                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02109                         break;
02110                 case 16*1 + 13:         /* ABGR, 32-bit depth+RGB x-5-5-5 */
02111                         sw[0] = (int)(data >> 16);
02112                         EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]);
02113                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02114                         break;
02115                 case 16*2 + 13:         /* RGBA, 32-bit depth+RGB x-5-5-5 */
02116                         sw[0] = (int)(data >> 16);
02117                         EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]);
02118                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02119                         break;
02120                 case 16*3 + 13:         /* BGRA, 32-bit depth+RGB x-5-5-5 */
02121                         sw[0] = (int)(data >> 16);
02122                         EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]);
02123                         mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW;
02124                         break;
02125 
02126                 case 16*0 + 14:         /* ARGB, 32-bit depth+ARGB 1-5-5-5 */
02127                         sw[0] = (int)(data >> 16);
02128                         EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]);
02129                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02130                         break;
02131                 case 16*1 + 14:         /* ABGR, 32-bit depth+ARGB 1-5-5-5 */
02132                         sw[0] = (int)(data >> 16);
02133                         EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]);
02134                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02135                         break;
02136                 case 16*2 + 14:         /* RGBA, 32-bit depth+ARGB 1-5-5-5 */
02137                         sw[0] = (int)(data >> 16);
02138                         EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]);
02139                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02140                         break;
02141                 case 16*3 + 14:         /* BGRA, 32-bit depth+ARGB 1-5-5-5 */
02142                         sw[0] = (int)(data >> 16);
02143                         EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]);
02144                         mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW;
02145                         break;
02146 
02147                 case 16*0 + 15:         /* ARGB, 16-bit depth */
02148                 case 16*1 + 15:         /* ARGB, 16-bit depth */
02149                 case 16*2 + 15:         /* ARGB, 16-bit depth */
02150                 case 16*3 + 15:         /* ARGB, 16-bit depth */
02151                         sw[0] = (int)(data & 0xffff);
02152                         sw[1] = (int)(data >> 16);
02153                         mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4);
02154                         offset <<= 1;
02155                         break;
02156 
02157                 default:                        /* reserved */
02158                         return;
02159         }
02160 
02161         /* compute X,Y */
02162         x = (offset << 0) & ((1 << 10) - 1);
02163         y = (offset >> 10) & ((1 << 10) - 1);
02164 
02165         /* adjust the mask based on which half of the data is written */
02166         if (!ACCESSING_BITS_0_15)
02167                 mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW);
02168         if (!ACCESSING_BITS_16_31)
02169                 mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW);
02170 
02171         /* select the target buffer */
02172         destbuf = LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u);
02173 //      LOG(LOG_VOODOO,LOG_WARN)("destbuf %X lfbmode %X",destbuf, v->reg[lfbMode].u);
02174         switch (destbuf)
02175         {
02176                 case 0:                 /* front buffer */
02177                         dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
02178                         destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
02179                         break;
02180 
02181                 case 1:                 /* back buffer */
02182                         dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
02183                         destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
02184                         break;
02185 
02186                 default:                /* reserved */
02187                         E_Exit("reserved lfb write");
02188                         return;
02189         }
02190         depth = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
02191         depthmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
02192 
02193         /* simple case: no pipeline */
02194         if (!LFBMODE_ENABLE_PIXEL_PIPELINE(v->reg[lfbMode].u))
02195         {
02196                 DECLARE_DITHER_POINTERS_NO_DITHER_VAR;
02197                 UINT32 bufoffs;
02198 
02199                 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);
02200 
02201                 /* determine the screen Y */
02202                 scry = y;
02203                 if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
02204                         scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02205 
02206                 /* advance pointers to the proper row */
02207                 bufoffs = (unsigned long)((long)scry * (long)v->fbi.rowpixels + (long)x);
02208 
02209                 /* compute dithering */
02210                 COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y);
02211 
02212                 /* loop over up to two pixels */
02213                 for (pix = 0; mask; pix++)
02214                 {
02215                         /* make sure we care about this pixel */
02216                         if (mask & 0x0f)
02217                         {
02218                                 bool has_rgb = (mask & LFB_RGB_PRESENT) > 0;
02219                                 bool has_alpha = ((mask & LFB_ALPHA_PRESENT) > 0) && (FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u) > 0);
02220                                 bool has_depth = ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u));
02221                                 if (v->ogl && v->active) {
02222                                         if (has_rgb || has_alpha) {
02223                                                 // if enabling dithering: output is 565 not 888 anymore
02224 //                                              APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
02225                                                 voodoo_ogl_draw_pixel(x, scry, has_rgb, has_alpha, sr[pix], sg[pix], sb[pix], sa[pix]);
02226                                         }
02227                                         if (has_depth) {
02228 #if C_OPENGL
02229                                                 voodoo_ogl_draw_z(x, scry+1, sw[pix]);
02230 #endif
02231                                         }
02232                                 } else {
02233                                         /* write to the RGB buffer */
02234                                         if (has_rgb && bufoffs < destmax)
02235                                         {
02236                                                 /* apply dithering and write to the screen */
02237                                                 APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]);
02238                                                 dest[bufoffs] = (UINT16)((sr[pix] << 11) | (sg[pix] << 5) | sb[pix]);
02239                                         }
02240 
02241                                         /* make sure we have an aux buffer to write to */
02242                                         if (depth && bufoffs < depthmax)
02243                                         {
02244                                                 /* write to the alpha buffer */
02245                                                 if (has_alpha)
02246                                                         depth[bufoffs] = (UINT16)sa[pix];
02247 
02248                                                 /* write to the depth buffer */
02249                                                 if (has_depth)
02250                                                         depth[bufoffs] = (UINT16)sw[pix];
02251                                         }
02252                                 }
02253 
02254                                 /* track pixel writes to the frame buffer regardless of mask */
02255                                 v->reg[fbiPixelsOut].u++;
02256                         }
02257 
02258                         /* advance our pointers */
02259                         bufoffs++;
02260                         x++;
02261                         mask >>= 4;
02262                 }
02263         }
02264 
02265         /* tricky case: run the full pixel pipeline on the pixel */
02266         else
02267         {
02268                 DECLARE_DITHER_POINTERS;
02269 
02270                 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);
02271 
02272                 /* determine the screen Y */
02273                 scry = y;
02274                 if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
02275                         scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02276 
02277                 /* advance pointers to the proper row */
02278                 dest += (unsigned long)((long)scry * (long)v->fbi.rowpixels);
02279                 if (depth)
02280                         depth += (unsigned long)((long)scry * (long)v->fbi.rowpixels);
02281 
02282                 /* compute dithering */
02283                 COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y);
02284 
02285                 /* loop over up to two pixels */
02286                 for (pix = 0; mask; pix++)
02287                 {
02288                         /* make sure we care about this pixel */
02289                         if (mask & 0x0f)
02290                         {
02291                                 stats_block *stats = &v->fbi.lfb_stats;
02292                                 INT64 iterw;
02293                                 if (LFBMODE_WRITE_W_SELECT(v->reg[lfbMode].u)) {
02294                                         iterw = (UINT32) v->reg[zaColor].u << 16;
02295                                 } else {
02296                                         iterw = (UINT32) sw[pix] << 16;
02297                                 }
02298                                 INT32 iterz = sw[pix] << 12;
02299                                 rgb_union color;
02300                                 rgb_union iterargb = { 0 };
02301 
02302                                 /* apply clipping */
02303                                 if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u))
02304                                 {
02305                                         if (x < (INT32)((v->reg[clipLeftRight].u >> 16) & 0x3ff) ||
02306                                                 x >= (INT32)(v->reg[clipLeftRight].u & 0x3ff) ||
02307                                                 scry < (INT32)((v->reg[clipLowYHighY].u >> 16) & 0x3ff) ||
02308                                                 scry >= (INT32)(v->reg[clipLowYHighY].u & 0x3ff))
02309                                         {
02310                                                 stats->pixels_in++;
02311                                                 stats->clip_fail++;
02312                                                 goto nextpixel;
02313                                         }
02314                                 }
02315 
02316                                 /* pixel pipeline part 1 handles depth testing and stippling */
02317                                 // TODO: in the v->ogl case this macro doesn't really work with depth testing
02318                                 // PIXEL_PIPELINE_BEGIN(v, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw);
02319 // Start PIXEL_PIPE_BEGIN copy
02320                                         INT32 fogdepth, biasdepth;
02321                                         INT32 prefogr, prefogg, prefogb;
02322                                         INT32 r, g, b, a;
02323 
02324                                         (stats)->pixels_in++;
02325 
02326                                         /* apply clipping */
02327                                         /* note that for perf reasons, we assume the caller has done clipping */
02328 
02329                                         /* handle stippling */
02330                                         if (FBZMODE_ENABLE_STIPPLE(v->reg[fbzMode].u))
02331                                         {
02332                                                 /* rotate mode */
02333                                                 if (FBZMODE_STIPPLE_PATTERN(v->reg[fbzMode].u) == 0)
02334                                                 {
02335                                                         v->reg[stipple].u = (v->reg[stipple].u << 1) | (v->reg[stipple].u >> 31);
02336                                                         if ((v->reg[stipple].u & 0x80000000) == 0)
02337                                                         {
02338                                                                 goto skipdrawdepth;
02339                                                         }
02340                                                 }
02341 
02342                                                 /* pattern mode */
02343                                                 else
02344                                                 {
02345                                                         int stipple_index = ((y & 3) << 3) | (~x & 7);
02346                                                         if (((v->reg[stipple].u >> stipple_index) & 1) == 0)
02347                                                         {
02348                                                                 goto nextpixel;
02349                                                         }
02350                                                 }
02351                                         }
02352 // End PIXEL_PIPELINE_BEGIN COPY
02353 
02354                                 // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used
02355                                 fogdepth = biasdepth = (INT32) sw[pix];
02356 
02357                                 color.rgb.r = sr[pix];
02358                                 color.rgb.g = sg[pix];
02359                                 color.rgb.b = sb[pix];
02360                                 color.rgb.a = sa[pix];
02361 
02362                                 /* Perform depth testing */
02363                                 DEPTH_TEST(v, stats, x, v->reg[fbzMode].u);     
02364 
02365                                 /* apply chroma key */
02366                                 APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, color);
02367 
02368                                 /* apply alpha mask, and alpha testing */
02369                                 APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, color.rgb.a);
02370                                 APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, color.rgb.a);
02371 
02372 
02373                                 if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp mselect %8x",FBZCP_CC_MSELECT(v->reg[fbzColorPath].u));
02374                                 if (FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u) > 1) LOG_MSG("lfbw fpp mselect alpha %8x",FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u));
02375 
02376                                 if (FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u) != 0) {
02377                                         if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp rblend %8x",FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u));
02378                                 }
02379                                 if (FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u) != 0) {
02380                                         if (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u) != 0) LOG_MSG("lfbw fpp rblend alpha %8x",FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u));
02381                                 }
02382 
02383 
02384                                 INT32 blendr, blendg, blendb, blenda;
02385                                 rgb_union c_local;
02386 
02387                                 /* compute c_local */
02388                                 if (FBZCP_CC_LOCALSELECT_OVERRIDE(v->reg[fbzColorPath].u) == 0)
02389                                 {
02390                                         if (FBZCP_CC_LOCALSELECT(v->reg[fbzColorPath].u) == 0)  /* iterated RGB */
02391                                         {
02392 //                                              c_local.u = iterargb.u;
02393                                                 c_local.rgb.r = sr[pix];
02394                                                 c_local.rgb.g = sg[pix];
02395                                                 c_local.rgb.b = sb[pix];
02396                                         }
02397                                         else                                                                                    /* color0 RGB */
02398                                                 c_local.u = v->reg[color0].u;
02399                                 }
02400                                 else
02401                                 {
02402                                         LOG_MSG("lfbw fpp FBZCP_CC_LOCALSELECT_OVERRIDE set!");
02403 /*                                      if (!(texel.rgb.a & 0x80))                                      // iterated RGB
02404                                                 c_local.u = iterargb.u;
02405                                         else                                                                                    // color0 RGB
02406                                                 c_local.u = v->reg[color0].u; */
02407                                 }
02408 
02409                                 /* compute a_local */
02410                                 switch (FBZCP_CCA_LOCALSELECT(v->reg[fbzColorPath].u))
02411                                 {
02412                                         default:
02413                                         case 0:         /* iterated alpha */
02414 //                                              c_local.rgb.a = iterargb.rgb.a;
02415                                                 c_local.rgb.a = sa[pix];
02416                                                 break;
02417                                         case 1:         /* color0 alpha */
02418                                                 c_local.rgb.a = v->reg[color0].rgb.a;
02419                                                 break;
02420                                         case 2:         /* clamped iterated Z[27:20] */
02421                                         {
02422                                                 int temp;
02423                                                 CLAMPED_Z(iterz, v->reg[fbzColorPath].u, temp);
02424                                                 c_local.rgb.a = (UINT8)temp;
02425                                                 break;
02426                                         }
02427                                         case 3:         /* clamped iterated W[39:32] */
02428                                         {
02429                                                 int temp;
02430                                                 CLAMPED_W(iterw, v->reg[fbzColorPath].u, temp);                 /* Voodoo 2 only */
02431                                                 c_local.rgb.a = (UINT8)temp;
02432                                                 break;
02433                                         }
02434                                 }
02435 
02436                                 /* select zero or c_other */
02437                                 if (FBZCP_CC_ZERO_OTHER(v->reg[fbzColorPath].u) == 0) {
02438                                         r = sr[pix];
02439                                         g = sg[pix];
02440                                         b = sb[pix];
02441                                 } else {
02442                                         r = g = b = 0;
02443                                 }
02444 
02445                                 /* select zero or a_other */
02446                                 if (FBZCP_CCA_ZERO_OTHER(v->reg[fbzColorPath].u) == 0) {
02447                                         a = sa[pix];
02448                                 } else {
02449                                         a = 0;
02450                                 }
02451 
02452                                 /* subtract c_local */
02453                                 if (FBZCP_CC_SUB_CLOCAL(v->reg[fbzColorPath].u))
02454                                 {
02455                                         r -= c_local.rgb.r;
02456                                         g -= c_local.rgb.g;
02457                                         b -= c_local.rgb.b;
02458                                 }
02459 
02460                                 /* subtract a_local */
02461                                 if (FBZCP_CCA_SUB_CLOCAL(v->reg[fbzColorPath].u))
02462                                         a -= c_local.rgb.a;
02463 
02464                                 /* blend RGB */
02465                                 switch (FBZCP_CC_MSELECT(v->reg[fbzColorPath].u))
02466                                 {
02467                                         default:        /* reserved */
02468                                         case 0:         /* 0 */
02469                                                 blendr = blendg = blendb = 0;
02470                                                 break;
02471                                         case 1:         /* c_local */
02472                                                 blendr = c_local.rgb.r;
02473                                                 blendg = c_local.rgb.g;
02474                                                 blendb = c_local.rgb.b;
02475                                                 LOG_MSG("blend RGB c_local");
02476                                                 break;
02477                                         case 2:         /* a_other */
02478                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02479 //                                              blendr = blendg = blendb = c_other.rgb.a;
02480                                                 LOG_MSG("blend RGB a_other");
02481                                                 break;
02482                                         case 3:         /* a_local */
02483                                                 blendr = blendg = blendb = c_local.rgb.a;
02484                                                 LOG_MSG("blend RGB a_local");
02485                                                 break;
02486                                         case 4:         /* texture alpha */
02487                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02488 //                                              blendr = blendg = blendb = texel.rgb.a;
02489                                                 LOG_MSG("blend RGB texture alpha");
02490                                                 break;
02491                                         case 5:         /* texture RGB (Voodoo 2 only) */
02492                                                 blendr = blendg = blendb = 0; // HACK: Gotta fill them with something --J.C
02493 /*                                              blendr = texel.rgb.r;
02494                                                 blendg = texel.rgb.g;
02495                                                 blendb = texel.rgb.b; */
02496                                                 LOG_MSG("blend RGB texture RGB");
02497                                                 break;
02498                                 }
02499 
02500                                 /* blend alpha */
02501                                 switch (FBZCP_CCA_MSELECT(v->reg[fbzColorPath].u))
02502                                 {
02503                                         default:        /* reserved */
02504                                         case 0:         /* 0 */
02505                                                 blenda = 0;
02506                                                 break;
02507                                         case 1:         /* a_local */
02508                                                 blenda = c_local.rgb.a;
02509 //                                              LOG_MSG("blend alpha a_local");
02510                                                 break;
02511                                         case 2:         /* a_other */
02512                                                 blenda = 0; /* HACK: gotta fill it with something */
02513 //                                              blenda = c_other.rgb.a;
02514                                                 LOG_MSG("blend alpha a_other");
02515                                                 break;
02516                                         case 3:         /* a_local */
02517                                                 blenda = c_local.rgb.a;
02518                                                 LOG_MSG("blend alpha a_local");
02519                                                 break;
02520                                         case 4:         /* texture alpha */
02521                                                 blenda = 0; /* HACK: gotta fill it with something */
02522 //                                              blenda = texel.rgb.a;
02523                                                 LOG_MSG("blend alpha texture alpha");
02524                                                 break;
02525                                 }
02526 
02527                                 /* reverse the RGB blend */
02528                                 if (!FBZCP_CC_REVERSE_BLEND(v->reg[fbzColorPath].u))
02529                                 {
02530                                         blendr ^= 0xff;
02531                                         blendg ^= 0xff;
02532                                         blendb ^= 0xff;
02533                                 }
02534 
02535                                 /* reverse the alpha blend */
02536                                 if (!FBZCP_CCA_REVERSE_BLEND(v->reg[fbzColorPath].u))
02537                                         blenda ^= 0xff;
02538 
02539                                 /* do the blend */
02540                                 r = (r * (blendr + 1)) >> 8;
02541                                 g = (g * (blendg + 1)) >> 8;
02542                                 b = (b * (blendb + 1)) >> 8;
02543                                 a = (a * (blenda + 1)) >> 8;
02544 
02545                                 /* add clocal or alocal to RGB */
02546                                 switch (FBZCP_CC_ADD_ACLOCAL(v->reg[fbzColorPath].u))
02547                                 {
02548                                         case 3:         /* reserved */
02549                                         case 0:         /* nothing */
02550                                                 break;
02551                                         case 1:         /* add c_local */
02552                                                 r += c_local.rgb.r;
02553                                                 g += c_local.rgb.g;
02554                                                 b += c_local.rgb.b;
02555                                                 break;
02556                                         case 2:         /* add_alocal */
02557                                                 r += c_local.rgb.a;
02558                                                 g += c_local.rgb.a;
02559                                                 b += c_local.rgb.a;
02560                                                 break;
02561                                 }
02562 
02563                                 /* add clocal or alocal to alpha */
02564                                 if (FBZCP_CCA_ADD_ACLOCAL(v->reg[fbzColorPath].u))
02565                                         a += c_local.rgb.a;
02566 
02567                                 /* clamp */
02568                                 CLAMP(r, 0x00, 0xff);
02569                                 CLAMP(g, 0x00, 0xff);
02570                                 CLAMP(b, 0x00, 0xff);
02571                                 CLAMP(a, 0x00, 0xff);
02572 
02573                                 /* invert */
02574                                 if (FBZCP_CC_INVERT_OUTPUT(v->reg[fbzColorPath].u))
02575                                 {
02576                                         r ^= 0xff;
02577                                         g ^= 0xff;
02578                                         b ^= 0xff;
02579                                 }
02580                                 if (FBZCP_CCA_INVERT_OUTPUT(v->reg[fbzColorPath].u))
02581                                         a ^= 0xff;
02582 
02583                                 if (v->ogl && v->active) {
02584                                         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u)) {
02585 //                                              APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b);
02586                                                 voodoo_ogl_draw_pixel_pipeline(x, scry, r, g, b);
02587                                         }
02588 /*                                      if (depth && FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u)) {
02589                                                 if (FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u) == 0)
02590                                                         voodoo_ogl_draw_z(x, y, depthval&0xffff, depthval>>16);
02591 //                                              else
02592 //                                                      depth[XX] = a;
02593                                         } */
02594                                 } else {
02595                                         /* pixel pipeline part 2 handles color combine, fog, alpha, and final output */
02596                                         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);
02597 
02598                                         PIXEL_PIPELINE_FINISH(v, dither_lookup, x, dest, depth, v->reg[fbzMode].u);
02599                                 }
02600 
02601                                 PIXEL_PIPELINE_END(stats);
02602 nextpixel:
02603                         /* advance our pointers */
02604                         x++;
02605                         mask >>= 4;
02606                 }
02607         }
02608 }
02609 
02610 
02611 
02612 /*************************************
02613  *
02614  *  Voodoo texture RAM writes
02615  *
02616  *************************************/
02617 
02618 INT32 texture_w(UINT32 offset, UINT32 data) {
02619         int tmunum = (offset >> 19) & 0x03;
02620         LOG(LOG_VOODOO,LOG_WARN)("V3D:write TMU%x offset %X value %X", tmunum, offset, data);
02621 
02622         tmu_state *t;
02623 
02624         /* point to the right TMU */
02625         if (!(v->chipmask & (2 << tmunum)))
02626                 return 0;
02627         t = &v->tmu[tmunum];
02628 
02629         if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u))
02630                 E_Exit("Texture direct write!");
02631 
02632         /* update texture info if dirty */
02633         if (t->regdirty)
02634                 recompute_texture_params(t);
02635 
02636         /* swizzle the data */
02637         if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u))
02638                 data = FLIPENDIAN_INT32(data);
02639         if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u))
02640                 data = (data >> 16) | (data << 16);
02641 
02642         /* 8-bit texture case */
02643         if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8)
02644         {
02645                 int lod, tt, ts;
02646                 UINT32 tbaseaddr;
02647                 UINT8 *dest;
02648 
02649                 /* extract info */
02650                 lod = (offset >> 15) & 0x0f;
02651                 tt = (offset >> 7) & 0xff;
02652 
02653                 /* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */
02654                 if (TEXMODE_SEQ_8_DOWNLD(v->tmu[0].reg/*t->reg*/[textureMode].u))
02655                         ts = (offset << 2) & 0xfc;
02656                 else
02657                         ts = (offset << 1) & 0xfc;
02658 
02659                 /* validate parameters */
02660                 if (lod > 8)
02661                         return 0;
02662 
02663                 /* compute the base address */
02664                 tbaseaddr = t->lodoffset[lod];
02665                 tbaseaddr += (UINT32)((long)tt * (((long)t->wmask >> lod) + 1l) + (long)ts);
02666 
02667                 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);
02668 
02669                 /* write the four bytes in little-endian order */
02670                 dest = t->ram;
02671                 tbaseaddr &= t->mask;
02672 
02673                 bool changed = false;
02674                 if (dest[BYTE4_XOR_LE(tbaseaddr + 0)] != ((data >> 0) & 0xff)) {
02675                         dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff;
02676                         changed = true;
02677                 }
02678                 if (dest[BYTE4_XOR_LE(tbaseaddr + 1)] != ((data >> 8) & 0xff)) {
02679                         dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff;
02680                         changed = true;
02681                 }
02682                 if (dest[BYTE4_XOR_LE(tbaseaddr + 2)] != ((data >> 16) & 0xff)) {
02683                         dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff;
02684                         changed = true;
02685                 }
02686                 if (dest[BYTE4_XOR_LE(tbaseaddr + 3)] != ((data >> 24) & 0xff)) {
02687                         dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff;
02688                         changed = true;
02689                 }
02690 
02691                 if (changed && v->ogl && v->active) {
02692                         voodoo_ogl_texture_clear(t->lodoffset[lod],tmunum);
02693                         voodoo_ogl_texture_clear(t->lodoffset[t->lodmin],tmunum);
02694                 }
02695         }
02696 
02697         /* 16-bit texture case */
02698         else
02699         {
02700                 int lod, tt, ts;
02701                 UINT32 tbaseaddr;
02702                 UINT16 *dest;
02703 
02704                 /* extract info */
02705                 // tmunum = (offset >> 19) & 0x03;
02706                 lod = (offset >> 15) & 0x0f;
02707                 tt = (offset >> 7) & 0xff;
02708                 ts = (offset << 1) & 0xfe;
02709 
02710                 /* validate parameters */
02711                 if (lod > 8)
02712                         return 0;
02713 
02714                 /* compute the base address */
02715                 tbaseaddr = t->lodoffset[lod];
02716                 tbaseaddr += (UINT32)(2l * ((long)tt * (((long)t->wmask >> lod) + 1l) + (long)ts));
02717 
02718                 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);
02719 
02720                 /* write the two words in little-endian order */
02721                 dest = (UINT16 *)t->ram;
02722                 tbaseaddr &= t->mask;
02723                 tbaseaddr >>= 1;
02724 
02725                 bool changed = false;
02726                 if (dest[BYTE_XOR_LE(tbaseaddr + 0)] != ((data >> 0) & 0xffff)) {
02727                         dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff;
02728                         changed = true;
02729                 }
02730                 if (dest[BYTE_XOR_LE(tbaseaddr + 1)] != ((data >> 16) & 0xffff)) {
02731                         dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff;
02732                         changed = true;
02733                 }
02734 
02735                 if (changed && v->ogl && v->active) {
02736                         voodoo_ogl_texture_clear(t->lodoffset[lod],tmunum);
02737                         voodoo_ogl_texture_clear(t->lodoffset[t->lodmin],tmunum);
02738                 }
02739         }
02740 
02741         return 0;
02742 }
02743 
02744 
02745 
02746 /*************************************
02747  *
02748  *  Handle a register read
02749  *
02750  *************************************/
02751 
02752 UINT32 register_r(UINT32 offset)
02753 {
02754         UINT32 regnum  = (offset) & 0xff;
02755 
02756 //      LOG(LOG_VOODOO,LOG_WARN)("Voodoo:read chip %x reg %x (%s)", chips, regnum<<2, voodoo_reg_name[regnum]);
02757 
02758         /* first make sure this register is readable */
02759         if (!(v->regaccess[regnum] & REGISTER_READ))
02760         {
02761                 return 0xffffffff;
02762         }
02763 
02764         UINT32 result;
02765 
02766         /* default result is the FBI register value */
02767         result = v->reg[regnum].u;
02768 
02769         /* some registers are dynamic; compute them */
02770         switch (regnum)
02771         {
02772                 case status:
02773                         CPU_Core_Dyn_X86_SaveDHFPUState();
02774 
02775                         /* start with a blank slate */
02776                         result = 0;
02777 
02778                         /* bits 5:0 are the PCI FIFO free space */
02779                         result |= 0x3fu << 0u;
02780 
02781                         /* bit 6 is the vertical retrace */
02782                         //result |= v->fbi.vblank << 6;
02783                         result |= (Voodoo_GetRetrace() ? 0x40u : 0u);
02784 
02785 
02786                         /* bit 7 is FBI graphics engine busy */
02787                         if (v->pci.op_pending)
02788                                 result |= 1 << 7;
02789 
02790                         /* bit 8 is TREX busy */
02791                         if (v->pci.op_pending)
02792                                 result |= 1 << 8;
02793 
02794                         /* bit 9 is overall busy */
02795                         if (v->pci.op_pending)
02796                                 result |= 1 << 9;
02797 
02798                         /* bits 11:10 specifies which buffer is visible */
02799                         result |= (UINT32)(v->fbi.frontbuf << 10);
02800 
02801                         /* bits 27:12 indicate memory FIFO freespace */
02802                         result |= 0xffffu << 12u;
02803 
02804                         /* bits 30:28 are the number of pending swaps */
02805                         result |= 0u << 28u;
02806 
02807                         /* bit 31 is not used */
02808 
02809                         CPU_Core_Dyn_X86_RestoreDHFPUState();
02810 
02811                         break;
02812 
02813                 case hvRetrace:
02814                         if (v->type < VOODOO_2)
02815                                 break;
02816 
02817                         CPU_Core_Dyn_X86_SaveDHFPUState();
02818 
02819                         /* start with a blank slate */
02820                         result = 0;
02821 
02822                         result |= ((Bit32u)(Voodoo_GetVRetracePosition() * 0x1fff)) & 0x1fff;
02823                         result |= (((Bit32u)(Voodoo_GetHRetracePosition() * 0x7ff)) & 0x7ff) << 16;
02824 
02825                         CPU_Core_Dyn_X86_RestoreDHFPUState();
02826                         break;
02827 
02828                 /* bit 2 of the initEnable register maps this to dacRead */
02829                 case fbiInit2:
02830                         if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
02831                                 result = v->dac.read_result;
02832                         break;
02833 
02834 /*              case fbiInit3:
02835                         if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable))
02836                                 result = 0;
02837                         break;
02838 
02839                 case fbiInit6:
02840                         if (v->type < VOODOO_2)
02841                                 break;
02842                         result &= 0xffffe7ff;
02843                         result |= 0x1000;
02844                         break; */
02845 
02846                 /* all counters are 24-bit only */
02847                 case fbiPixelsIn:
02848                 case fbiChromaFail:
02849                 case fbiZfuncFail:
02850                 case fbiAfuncFail:
02851                 case fbiPixelsOut:
02852                         update_statistics(v, true);
02853                 case fbiTrianglesOut:
02854                         result = v->reg[regnum].u & 0xffffff;
02855                         break;
02856 
02857         }
02858 
02859         return result;
02860 }
02861 
02862 
02863 
02864 /*************************************
02865  *
02866  *  Handle an LFB read
02867  *
02868  *************************************/
02869 UINT32 lfb_r(UINT32 offset)
02870 {
02871         LOG(LOG_VOODOO,LOG_WARN)("Voodoo:read LFB offset %X", offset);
02872         UINT16 *buffer;
02873         UINT32 bufmax;
02874         UINT32 bufoffs;
02875         UINT32 data;
02876         int x, y, scry;
02877         UINT32 destbuf;
02878 
02879         /* compute X,Y */
02880         x = (offset << 1) & 0x3fe;
02881         y = (offset >> 9) & 0x3ff;
02882 
02883         /* select the target buffer */
02884         destbuf = LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u);
02885         switch (destbuf)
02886         {
02887                 case 0:                 /* front buffer */
02888                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
02889                         bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2;
02890                         break;
02891 
02892                 case 1:                 /* back buffer */
02893                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
02894                         bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2;
02895                         break;
02896 
02897                 case 2:                 /* aux buffer */
02898                         if (v->fbi.auxoffs == (UINT32)(~0))
02899                                 return 0xffffffff;
02900                         buffer = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs);
02901                         bufmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2;
02902                         break;
02903 
02904                 default:                /* reserved */
02905                         return 0xffffffff;
02906         }
02907 
02908         /* determine the screen Y */
02909         scry = y;
02910         if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u))
02911                 scry = ((int)v->fbi.yorigin - y) & 0x3ff;
02912 
02913         if (v->ogl && v->active) {
02914                 data = voodoo_ogl_read_pixel(x, scry+1);
02915         } else {
02916                 /* advance pointers to the proper row */
02917                 bufoffs = (unsigned long)((long)scry * (long)v->fbi.rowpixels + (long)x);
02918                 if (bufoffs >= bufmax){
02919                         LOG_MSG("LFB_R: Buffer offset out of bounds x=%i y=%i offset=%08X bufoffs=%08X\n", x, y, offset, (UINT32) bufoffs);
02920                         return 0xffffffff;
02921                 }
02922 
02923                 /* compute the data */
02924                 data = (unsigned int)buffer[bufoffs + 0u] | (unsigned int)(buffer[bufoffs + 1u] << 16u);
02925         }
02926 
02927         /* word swapping */
02928         if (LFBMODE_WORD_SWAP_READS(v->reg[lfbMode].u))
02929                 data = (data << 16u) | (data >> 16u);
02930 
02931         /* byte swizzling */
02932         if (LFBMODE_BYTE_SWIZZLE_READS(v->reg[lfbMode].u))
02933                 data = FLIPENDIAN_INT32(data);
02934 
02935         if (LOG_LFB) LOG(LOG_VOODOO,LOG_WARN)("VOODOO.LFB:read (%d,%d) = %08X\n", x, y, data);
02936         return data;
02937 }
02938 
02939 
02940 void voodoo_w(UINT32 offset, UINT32 data, UINT32 mask) {
02941         if ((offset & (0xc00000/4)) == 0)
02942                 register_w(offset, data);
02943         else if ((offset & (0x800000/4)) == 0)
02944                 lfb_w(offset, data, mask);
02945         else
02946                 texture_w(offset, data);
02947 }
02948 
02949 UINT32 voodoo_r(UINT32 offset) {
02950         if ((offset & (0xc00000/4)) == 0)
02951                 return register_r(offset);
02952         else if ((offset & (0x800000/4)) == 0)
02953                 return lfb_r(offset);
02954 
02955         return 0xffffffff;
02956 }
02957 
02958 
02959 
02960 /***************************************************************************
02961     DEVICE INTERFACE
02962 ***************************************************************************/
02963 
02964 /*-------------------------------------------------
02965     device start callback
02966 -------------------------------------------------*/
02967 
02968 void voodoo_init(int type) {
02969         v->active = false;
02970 
02971         v->type = VOODOO_1_DTMU;
02972 
02973         switch (type) {
02974                 case VOODOO_1:
02975                         break;
02976                 case VOODOO_1_DTMU:
02977                         v->type = VOODOO_1_DTMU;
02978                         break;
02979                 case VOODOO_2:
02980                         v->type = VOODOO_2;
02981                         break;
02982                 default:
02983                         LOG_MSG("invalid voodoo card type initialization [%x]",type);
02984                         break;
02985         }
02986 
02987         memset(v->reg, 0, sizeof(v->reg));
02988 
02989         v->fbi.vblank_flush_pending = false;
02990         v->pci.op_pending = false;
02991         v->dac.read_result = 0;
02992 
02993         v->output_on = false;
02994         v->clock_enabled = false;
02995         v->ogl_dimchange = true;
02996         v->send_config = false;
02997 
02998         memset(v->dac.reg, 0, sizeof(v->dac.reg));
02999 
03000         v->next_rasterizer = 0;
03001         for (UINT32 rct=0; rct<MAX_RASTERIZERS; rct++)
03002                 v->rasterizer[rct] = raster_info();
03003 
03004         v->thread_stats = new stats_block[1];
03005         v->thread_stats[0].pixels_in = 0;
03006         v->thread_stats[0].pixels_out = 0;
03007         v->thread_stats[0].chroma_fail = 0;
03008         v->thread_stats[0].zfunc_fail = 0;
03009         v->thread_stats[0].afunc_fail = 0;
03010         v->thread_stats[0].clip_fail = 0;
03011         v->thread_stats[0].stipple_count = 0;
03012 
03013         v->alt_regmap = false;
03014         v->regnames = voodoo_reg_name;
03015 
03016         /* create a table of precomputed 1/n and log2(n) values */
03017         /* n ranges from 1.0000 to 2.0000 */
03018         for (UINT32 val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++)
03019         {
03020                 UINT32 value = (1 << RECIPLOG_LOOKUP_BITS) + val;
03021                 voodoo_reciplog[val*2 + 0] = (1u << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value;
03022                 voodoo_reciplog[val*2 + 1] = (UINT32)(LOGB2((double)value / (double)(1u << RECIPLOG_LOOKUP_BITS)) * (double)(1u << RECIPLOG_LOOKUP_PREC));
03023         }
03024 
03025         for (UINT32 val = 0; val < RASTER_HASH_SIZE; val++)
03026                 v->raster_hash[val] = NULL;
03027 
03028         /* create dithering tables */
03029         for (UINT32 val = 0; val < 256*16*2; val++)
03030         {
03031                 int g = (val >> 0) & 1;
03032                 int x = (val >> 1) & 3;
03033                 int color = (val >> 3) & 0xff;
03034                 int y = (val >> 11) & 3;
03035 
03036                 if (!g)
03037                 {
03038                         dither4_lookup[val] = (UINT8)(DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3);
03039                         dither2_lookup[val] = (UINT8)(DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3);
03040                 }
03041                 else
03042                 {
03043                         dither4_lookup[val] = (UINT8)(DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2);
03044                         dither2_lookup[val] = (UINT8)(DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2);
03045                 }
03046         }
03047 
03048         v->tmu_config = 0x11;   // revision 1
03049 
03050         UINT32 fbmemsize = 0;
03051         UINT32 tmumem0 = 0;
03052         UINT32 tmumem1 = 0;
03053 
03054         /* configure type-specific values */
03055         switch (v->type)
03056         {
03057                 case VOODOO_1:
03058                         v->regaccess = voodoo_register_access;
03059                         fbmemsize = 2;
03060                         tmumem0 = 2;
03061                         break;
03062 
03063                 case VOODOO_1_DTMU:
03064                         v->regaccess = voodoo_register_access;
03065                         fbmemsize = 4;
03066                         tmumem0 = 4;
03067                         tmumem1 = 4;
03068                         break;
03069 
03070                 case VOODOO_2:
03071                         v->regaccess = voodoo2_register_access;
03072                         fbmemsize = 4;
03073                         tmumem0 = 4;
03074                         tmumem1 = 4;
03075                         v->tmu_config |= 0x800;
03076                         break;
03077 
03078                 default:
03079                         E_Exit("Unsupported voodoo card in voodoo_start!");
03080                         break;
03081         }
03082 
03083         if (tmumem1 != 0)
03084                 v->tmu_config |= 0xc0;  // two TMUs
03085 
03086         v->chipmask = 0x01;
03087 
03088         /* set up the PCI FIFO */
03089         v->pci.fifo.size = 64*2;
03090 
03091         /* set up frame buffer */
03092         init_fbi(v, &v->fbi, (int)(fbmemsize << 20));
03093 
03094         v->fbi.rowpixels = v->fbi.width;
03095 
03096         v->tmu[0].ncc[0].palette = NULL;
03097         v->tmu[0].ncc[1].palette = NULL;
03098         v->tmu[1].ncc[0].palette = NULL;
03099         v->tmu[1].ncc[1].palette = NULL;
03100         v->tmu[0].ncc[0].palettea = NULL;
03101         v->tmu[0].ncc[1].palettea = NULL;
03102         v->tmu[1].ncc[0].palettea = NULL;
03103         v->tmu[1].ncc[1].palettea = NULL;
03104 
03105         v->tmu[0].ram = NULL;
03106         v->tmu[1].ram = NULL;
03107         v->tmu[0].lookup = NULL;
03108         v->tmu[1].lookup = NULL;
03109 
03110         /* build shared TMU tables */
03111         init_tmu_shared(&v->tmushare);
03112 
03113         /* set up the TMUs */
03114         init_tmu(v, &v->tmu[0], &v->reg[0x100], (int)(tmumem0 << 20));
03115         v->chipmask |= 0x02;
03116         if (tmumem1 != 0)
03117         {
03118                 init_tmu(v, &v->tmu[1], &v->reg[0x200], (int)(tmumem1 << 20));
03119                 v->chipmask |= 0x04;
03120                 v->tmu_config |= 0x40;
03121         }
03122 
03123         /* initialize some registers */
03124         v->pci.init_enable = 0;
03125         v->reg[fbiInit0].u = (UINT32)((1 << 4) | (0x10 << 6));
03126         v->reg[fbiInit1].u = (UINT32)((1 << 1) | (1 << 8) | (1 << 12) | (2 << 20));
03127         v->reg[fbiInit2].u = (UINT32)((1 << 6) | (0x100 << 23));
03128         v->reg[fbiInit3].u = (UINT32)((2 << 13) | (0xf << 17));
03129         v->reg[fbiInit4].u = (UINT32)(1 << 0);
03130 
03131         /* do a soft reset to reset everything else */
03132         soft_reset(v);
03133 
03134         recompute_video_memory(v);
03135 }
03136 
03137 void voodoo_shutdown() {
03138         if (v->ogl)
03139                 voodoo_ogl_shutdown(v);
03140 
03141         if (v!=NULL) {
03142                 free(v->fbi.ram);
03143                 if (v->tmu[0].ram != NULL) {
03144                         free(v->tmu[0].ram);
03145                         v->tmu[0].ram = NULL;
03146                 }
03147                 if (v->tmu[1].ram != NULL) {
03148                         free(v->tmu[1].ram);
03149                         v->tmu[1].ram = NULL;
03150                 }
03151                 delete[] v->thread_stats;
03152                 v->active=false;
03153         }
03154 }
03155 
03156 
03157 /***************************************************************************
03158     COMMAND HANDLERS
03159 ***************************************************************************/
03160 
03161 /*-------------------------------------------------
03162     fastfill - execute the 'fastfill'
03163     command
03164 -------------------------------------------------*/
03165 
03166 void fastfill(voodoo_state *v)
03167 {
03168         int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff;
03169         int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff;
03170         int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff;
03171         int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff;
03172 
03173         poly_extent extents[64];
03174         UINT16 dithermatrix[16];
03175         UINT16 *drawbuf = NULL;
03176         int extnum, x, y;
03177 
03178         /* if we're not clearing either, take no time */
03179         if (!FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u))
03180                 return;
03181 
03182         /* are we clearing the RGB buffer? */
03183         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
03184         {
03185                 /* determine the draw buffer */
03186                 int destbuf = FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
03187                 switch (destbuf)
03188                 {
03189                         case 0:         /* front buffer */
03190                                 drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
03191                                 break;
03192 
03193                         case 1:         /* back buffer */
03194                                 drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
03195                                 break;
03196 
03197                         default:        /* reserved */
03198                                 break;
03199                 }
03200 
03201                 /* determine the dither pattern */
03202                 for (y = 0; y < 4; y++)
03203                 {
03204                         DECLARE_DITHER_POINTERS_NO_DITHER_VAR;
03205                         COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y);
03206                         for (x = 0; x < 4; x++)
03207                         {
03208                                 int r = v->reg[color1].rgb.r;
03209                                 int g = v->reg[color1].rgb.g;
03210                                 int b = v->reg[color1].rgb.b;
03211 
03212                                 APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, r, g, b);
03213                                 dithermatrix[y*4 + x] = (UINT16)((r << 11) | (g << 5) | b);
03214                         }
03215                 }
03216         }
03217 
03218         /* fill in a block of extents */
03219         extents[0].startx = sx;
03220         extents[0].stopx = ex;
03221         for (extnum = 1; (size_t)extnum < ARRAY_LENGTH(extents); extnum++)
03222                 extents[extnum] = extents[0];
03223 
03224         poly_extra_data *extra = new poly_extra_data;
03225 
03226         if (v->ogl && v->active) {
03227                 voodoo_ogl_fastfill();
03228         } else {
03229 
03230                 /* iterate over blocks of extents */
03231                 for (y = sy; y < ey; y += (int)ARRAY_LENGTH(extents))
03232                 {
03233                         int count = MIN(((size_t)(ey - y)), ARRAY_LENGTH(extents));
03234 
03235                         extra->state = v;
03236                         memcpy(extra->dither, dithermatrix, sizeof(extra->dither));
03237 
03238                         poly_render_triangle_custom(drawbuf, y, count, extents, extra);
03239                 }
03240         }
03241         delete extra;
03242 }
03243 
03244 
03245 /*-------------------------------------------------
03246     swapbuffer - execute the 'swapbuffer'
03247     command
03248 -------------------------------------------------*/
03249 
03250 void swapbuffer(voodoo_state *v, UINT32 data)
03251 {
03252         /* set the don't swap value for Voodoo 2 */
03253         v->fbi.vblank_dont_swap = ((data >> 9) & 1)>0;
03254 
03255         voodoo_swap_buffers(v);
03256 }
03257 
03258 
03259 /*-------------------------------------------------
03260     triangle - execute the 'triangle'
03261     command
03262 -------------------------------------------------*/
03263 
03264 void triangle(voodoo_state *v)
03265 {
03266         int texcount = 0;
03267         UINT16 *drawbuf;
03268         int destbuf;
03269 
03270         /* determine the number of TMUs involved */
03271         texcount = 0;
03272         if (!FBIINIT3_DISABLE_TMUS(v->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(v->reg[fbzColorPath].u))
03273         {
03274                 texcount = 1;
03275                 if (v->chipmask & 0x04)
03276                         texcount = 2;
03277         }
03278 
03279         /* perform subpixel adjustments */
03280         // ????????
03281         if (!v->ogl && FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
03282 //      if (FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u))
03283         {
03284                 INT32 dx = 8 - (v->fbi.ax & 15);
03285                 INT32 dy = 8 - (v->fbi.ay & 15);
03286 
03287                 /* adjust iterated R,G,B,A and W/Z */
03288                 v->fbi.startr += (dy * v->fbi.drdy + dx * v->fbi.drdx) >> 4;
03289                 v->fbi.startg += (dy * v->fbi.dgdy + dx * v->fbi.dgdx) >> 4;
03290                 v->fbi.startb += (dy * v->fbi.dbdy + dx * v->fbi.dbdx) >> 4;
03291                 v->fbi.starta += (dy * v->fbi.dady + dx * v->fbi.dadx) >> 4;
03292                 v->fbi.startw += (dy * v->fbi.dwdy + dx * v->fbi.dwdx) >> 4;
03293                 v->fbi.startz += mul_32x32_shift(dy, v->fbi.dzdy, 4) + mul_32x32_shift(dx, v->fbi.dzdx, 4);
03294 
03295                 /* adjust iterated W/S/T for TMU 0 */
03296                 if (texcount >= 1)
03297                 {
03298                         v->tmu[0].startw += (dy * v->tmu[0].dwdy + dx * v->tmu[0].dwdx) >> 4;
03299                         v->tmu[0].starts += (dy * v->tmu[0].dsdy + dx * v->tmu[0].dsdx) >> 4;
03300                         v->tmu[0].startt += (dy * v->tmu[0].dtdy + dx * v->tmu[0].dtdx) >> 4;
03301 
03302                         /* adjust iterated W/S/T for TMU 1 */
03303                         if (texcount >= 2)
03304                         {
03305                                 v->tmu[1].startw += (dy * v->tmu[1].dwdy + dx * v->tmu[1].dwdx) >> 4;
03306                                 v->tmu[1].starts += (dy * v->tmu[1].dsdy + dx * v->tmu[1].dsdx) >> 4;
03307                                 v->tmu[1].startt += (dy * v->tmu[1].dtdy + dx * v->tmu[1].dtdx) >> 4;
03308                         }
03309                 }
03310         }
03311 
03312         /* determine the draw buffer */
03313         destbuf = FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u);
03314         switch (destbuf)
03315         {
03316                 case 0:         /* front buffer */
03317                         drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
03318                         break;
03319 
03320                 case 1:         /* back buffer */
03321                         drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]);
03322                         break;
03323 
03324                 default:        /* reserved */
03325                         return;
03326         }
03327 
03328         /* find a rasterizer that matches our current state */
03329         triangle_create_work_item(v, drawbuf, texcount);
03330 
03331         /* update stats */
03332         v->reg[fbiTrianglesOut].u++;
03333 }
03334 
03335 
03336 /*-------------------------------------------------
03337     begin_triangle - execute the 'beginTri'
03338     command
03339 -------------------------------------------------*/
03340 
03341 static void begin_triangle(voodoo_state *v)
03342 {
03343         setup_vertex *sv = &v->fbi.svert[2];
03344 
03345         /* extract all the data from registers */
03346         sv->x = v->reg[sVx].f;
03347         sv->y = v->reg[sVy].f;
03348         sv->wb = v->reg[sWb].f;
03349         sv->w0 = v->reg[sWtmu0].f;
03350         sv->s0 = v->reg[sS_W0].f;
03351         sv->t0 = v->reg[sT_W0].f;
03352         sv->w1 = v->reg[sWtmu1].f;
03353         sv->s1 = v->reg[sS_Wtmu1].f;
03354         sv->t1 = v->reg[sT_Wtmu1].f;
03355         sv->a = v->reg[sAlpha].f;
03356         sv->r = v->reg[sRed].f;
03357         sv->g = v->reg[sGreen].f;
03358         sv->b = v->reg[sBlue].f;
03359 
03360         /* spread it across all three verts and reset the count */
03361         v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2];
03362         v->fbi.sverts = 1;
03363 }
03364 
03365 
03366 /*-------------------------------------------------
03367     draw_triangle - execute the 'DrawTri'
03368     command
03369 -------------------------------------------------*/
03370 
03371 static void draw_triangle(voodoo_state *v)
03372 {
03373         setup_vertex *sv = &v->fbi.svert[2];
03374 
03375         /* for strip mode, shuffle vertex 1 down to 0 */
03376         if (!(v->reg[sSetupMode].u & (1 << 16)))
03377                 v->fbi.svert[0] = v->fbi.svert[1];
03378 
03379         /* copy 2 down to 1 regardless */
03380         v->fbi.svert[1] = v->fbi.svert[2];
03381 
03382         /* extract all the data from registers */
03383         sv->x = v->reg[sVx].f;
03384         sv->y = v->reg[sVy].f;
03385         sv->wb = v->reg[sWb].f;
03386         sv->w0 = v->reg[sWtmu0].f;
03387         sv->s0 = v->reg[sS_W0].f;
03388         sv->t0 = v->reg[sT_W0].f;
03389         sv->w1 = v->reg[sWtmu1].f;
03390         sv->s1 = v->reg[sS_Wtmu1].f;
03391         sv->t1 = v->reg[sT_Wtmu1].f;
03392         sv->a = v->reg[sAlpha].f;
03393         sv->r = v->reg[sRed].f;
03394         sv->g = v->reg[sGreen].f;
03395         sv->b = v->reg[sBlue].f;
03396 
03397         /* if we have enough verts, go ahead and draw */
03398         if (++v->fbi.sverts >= 3)
03399                 setup_and_draw_triangle(v);
03400 }
03401 
03402 
03403 /*-------------------------------------------------
03404     setup_and_draw_triangle - process the setup
03405     parameters and render the triangle
03406 -------------------------------------------------*/
03407 
03408 static void setup_and_draw_triangle(voodoo_state *v)
03409 {
03410         float dx1, dy1, dx2, dy2;
03411         float divisor, tdiv;
03412 
03413         /* grab the X/Ys at least */
03414         v->fbi.ax = (INT16)(v->fbi.svert[0].x * 16.0);
03415         v->fbi.ay = (INT16)(v->fbi.svert[0].y * 16.0);
03416         v->fbi.bx = (INT16)(v->fbi.svert[1].x * 16.0);
03417         v->fbi.by = (INT16)(v->fbi.svert[1].y * 16.0);
03418         v->fbi.cx = (INT16)(v->fbi.svert[2].x * 16.0);
03419         v->fbi.cy = (INT16)(v->fbi.svert[2].y * 16.0);
03420 
03421         /* compute the divisor */
03422         divisor = 1.0f / ((v->fbi.svert[0].x - v->fbi.svert[1].x) * (v->fbi.svert[0].y - v->fbi.svert[2].y) -
03423                                           (v->fbi.svert[0].x - v->fbi.svert[2].x) * (v->fbi.svert[0].y - v->fbi.svert[1].y));
03424 
03425         /* backface culling */
03426         if (v->reg[sSetupMode].u & 0x20000)
03427         {
03428                 int culling_sign = (v->reg[sSetupMode].u >> 18) & 1;
03429                 int divisor_sign = (divisor < 0);
03430 
03431                 /* if doing strips and ping pong is enabled, apply the ping pong */
03432                 if ((v->reg[sSetupMode].u & 0x90000) == 0x00000)
03433                         culling_sign ^= (v->fbi.sverts - 3) & 1;
03434 
03435                 /* if our sign matches the culling sign, we're done for */
03436                 if (divisor_sign == culling_sign)
03437                         return;
03438         }
03439 
03440         /* compute the dx/dy values */
03441         dx1 = v->fbi.svert[0].y - v->fbi.svert[2].y;
03442         dx2 = v->fbi.svert[0].y - v->fbi.svert[1].y;
03443         dy1 = v->fbi.svert[0].x - v->fbi.svert[1].x;
03444         dy2 = v->fbi.svert[0].x - v->fbi.svert[2].x;
03445 
03446         /* set up R,G,B */
03447         tdiv = divisor * 4096.0f;
03448         if (v->reg[sSetupMode].u & (1 << 0))
03449         {
03450                 v->fbi.startr = (INT32)(v->fbi.svert[0].r * 4096.0f);
03451                 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);
03452                 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);
03453                 v->fbi.startg = (INT32)(v->fbi.svert[0].g * 4096.0f);
03454                 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);
03455                 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);
03456                 v->fbi.startb = (INT32)(v->fbi.svert[0].b * 4096.0f);
03457                 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);
03458                 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);
03459         }
03460 
03461         /* set up alpha */
03462         if (v->reg[sSetupMode].u & (1 << 1))
03463         {
03464                 v->fbi.starta = (INT32)(v->fbi.svert[0].a * 4096.0);
03465                 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);
03466                 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);
03467         }
03468 
03469         /* set up Z */
03470         if (v->reg[sSetupMode].u & (1 << 2))
03471         {
03472                 v->fbi.startz = (INT32)(v->fbi.svert[0].z * 4096.0);
03473                 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);
03474                 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);
03475         }
03476 
03477         /* set up Wb */
03478         tdiv = divisor * 65536.0f * 65536.0f;
03479         if (v->reg[sSetupMode].u & (1 << 3))
03480         {
03481                 v->fbi.startw = v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].wb * 65536.0f * 65536.0f);
03482                 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);
03483                 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);
03484         }
03485 
03486         /* set up W0 */
03487         if (v->reg[sSetupMode].u & (1 << 4))
03488         {
03489                 v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].w0 * 65536.0f * 65536.0f);
03490                 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);
03491                 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);
03492         }
03493 
03494         /* set up S0,T0 */
03495         if (v->reg[sSetupMode].u & (1 << 5))
03496         {
03497                 v->tmu[0].starts = v->tmu[1].starts = (INT64)(v->fbi.svert[0].s0 * 65536.0f * 65536.0f);
03498                 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);
03499                 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);
03500                 v->tmu[0].startt = v->tmu[1].startt = (INT64)(v->fbi.svert[0].t0 * 65536.0f * 65536.0f);
03501                 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);
03502                 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);
03503         }
03504 
03505         /* set up W1 */
03506         if (v->reg[sSetupMode].u & (1 << 6))
03507         {
03508                 v->tmu[1].startw = (INT64)(v->fbi.svert[0].w1 * 65536.0f * 65536.0f);
03509                 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);
03510                 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);
03511         }
03512 
03513         /* set up S1,T1 */
03514         if (v->reg[sSetupMode].u & (1 << 7))
03515         {
03516                 v->tmu[1].starts = (INT64)(v->fbi.svert[0].s1 * 65536.0f * 65536.0f);
03517                 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);
03518                 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);
03519                 v->tmu[1].startt = (INT64)(v->fbi.svert[0].t1 * 65536.0f * 65536.0f);
03520                 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);
03521                 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);
03522         }
03523 
03524         /* draw the triangle */
03525         triangle(v);
03526 }
03527 
03528 
03529 /*-------------------------------------------------
03530     triangle_create_work_item - finish triangle
03531     setup and create the work item
03532 -------------------------------------------------*/
03533 
03534 void triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount)
03535 {
03536         poly_extra_data *extra = new poly_extra_data;
03537         raster_info *info  = find_rasterizer(v, texcount);
03538         poly_vertex vert[3];
03539 
03540         /* fill in the vertex data */
03541         vert[0].x = (float)v->fbi.ax * (1.0f / 16.0f);
03542         vert[0].y = (float)v->fbi.ay * (1.0f / 16.0f);
03543         vert[1].x = (float)v->fbi.bx * (1.0f / 16.0f);
03544         vert[1].y = (float)v->fbi.by * (1.0f / 16.0f);
03545         vert[2].x = (float)v->fbi.cx * (1.0f / 16.0f);
03546         vert[2].y = (float)v->fbi.cy * (1.0f / 16.0f);
03547 
03548         /* fill in the extra data */
03549         extra->state = v;
03550         extra->info = info;
03551 
03552         /* fill in triangle parameters */
03553         extra->ax = v->fbi.ax;
03554         extra->ay = v->fbi.ay;
03555         extra->startr = v->fbi.startr;
03556         extra->startg = v->fbi.startg;
03557         extra->startb = v->fbi.startb;
03558         extra->starta = v->fbi.starta;
03559         extra->startz = v->fbi.startz;
03560         extra->startw = v->fbi.startw;
03561         extra->drdx = v->fbi.drdx;
03562         extra->dgdx = v->fbi.dgdx;
03563         extra->dbdx = v->fbi.dbdx;
03564         extra->dadx = v->fbi.dadx;
03565         extra->dzdx = v->fbi.dzdx;
03566         extra->dwdx = v->fbi.dwdx;
03567         extra->drdy = v->fbi.drdy;
03568         extra->dgdy = v->fbi.dgdy;
03569         extra->dbdy = v->fbi.dbdy;
03570         extra->dady = v->fbi.dady;
03571         extra->dzdy = v->fbi.dzdy;
03572         extra->dwdy = v->fbi.dwdy;
03573 
03574         /* fill in texture 0 parameters */
03575         if (texcount > 0)
03576         {
03577                 extra->starts0 = v->tmu[0].starts;
03578                 extra->startt0 = v->tmu[0].startt;
03579                 extra->startw0 = v->tmu[0].startw;
03580                 extra->ds0dx = v->tmu[0].dsdx;
03581                 extra->dt0dx = v->tmu[0].dtdx;
03582                 extra->dw0dx = v->tmu[0].dwdx;
03583                 extra->ds0dy = v->tmu[0].dsdy;
03584                 extra->dt0dy = v->tmu[0].dtdy;
03585                 extra->dw0dy = v->tmu[0].dwdy;
03586                 extra->lodbase0 = prepare_tmu(&v->tmu[0]);
03587 
03588                 /* fill in texture 1 parameters */
03589                 if (texcount > 1)
03590                 {
03591                         extra->starts1 = v->tmu[1].starts;
03592                         extra->startt1 = v->tmu[1].startt;
03593                         extra->startw1 = v->tmu[1].startw;
03594                         extra->ds1dx = v->tmu[1].dsdx;
03595                         extra->dt1dx = v->tmu[1].dtdx;
03596                         extra->dw1dx = v->tmu[1].dwdx;
03597                         extra->ds1dy = v->tmu[1].dsdy;
03598                         extra->dt1dy = v->tmu[1].dtdy;
03599                         extra->dw1dy = v->tmu[1].dwdy;
03600                         extra->lodbase1 = prepare_tmu(&v->tmu[1]);
03601                 }
03602         }
03603 
03604         extra->texcount = (unsigned int)texcount;
03605         extra->r_fbzColorPath = v->reg[fbzColorPath].u;
03606         extra->r_fbzMode = v->reg[fbzMode].u;
03607         extra->r_alphaMode = v->reg[alphaMode].u;
03608         extra->r_fogMode = v->reg[fogMode].u;
03609         extra->r_textureMode0 = (INT32)v->tmu[0].reg[textureMode].u;
03610         if (v->tmu[1].ram != NULL) extra->r_textureMode1 = (INT32)v->tmu[1].reg[textureMode].u;
03611 
03612         info->polys++;
03613 
03614         if (palette_changed && v->ogl && v->active) {
03615                 voodoo_ogl_invalidate_paltex();
03616                 palette_changed = false;
03617         }
03618 
03619         if (v->ogl && v->active) {
03620                 if (extra->info==NULL)  {
03621                         delete extra;
03622                         return;
03623                 }
03624                 voodoo_ogl_draw_triangle(extra);
03625         } else {
03626                 poly_render_triangle(drawbuf, info->callback, &vert[0], &vert[1], &vert[2], extra);
03627         }
03628 
03629         delete extra;
03630 }
03631 
03632 /***************************************************************************
03633     RASTERIZER MANAGEMENT
03634 ***************************************************************************/
03635 
03636 /*-------------------------------------------------
03637     add_rasterizer - add a rasterizer to our
03638     hash table
03639 -------------------------------------------------*/
03640 
03641 static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo)
03642 {
03643         raster_info *info = &v->rasterizer[v->next_rasterizer++];
03644         unsigned int hash = compute_raster_hash(cinfo);
03645 
03646         if (v->next_rasterizer > MAX_RASTERIZERS)
03647                 E_Exit("Out of space for new rasterizers!");
03648 
03649         /* make a copy of the info */
03650         *info = *cinfo;
03651 
03652         /* fill in the data */
03653         info->hits = 0;
03654         info->polys = 0;
03655 
03656         /* hook us into the hash table */
03657         info->next = v->raster_hash[hash];
03658         v->raster_hash[hash] = info;
03659 
03660         if (LOG_RASTERIZERS)
03661                 LOG_MSG("Adding rasterizer @ %p : %08X %08X %08X %08X %08X %08X (hash=%d)\n",
03662                                 (void*)((uintptr_t)(info->callback)),
03663                                 info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode,
03664                                 info->eff_tex_mode_0, info->eff_tex_mode_1, hash);
03665 
03666         return info;
03667 }
03668 
03669 
03670 /*-------------------------------------------------
03671     find_rasterizer - find a rasterizer that
03672     matches  our current parameters and return
03673     it, creating a new one if necessary
03674 -------------------------------------------------*/
03675 
03676 static raster_info *find_rasterizer(voodoo_state *v, int texcount)
03677 {
03678         raster_info *info, *prev = NULL;
03679         raster_info curinfo;
03680         unsigned int hash;
03681 
03682         /* build an info struct with all the parameters */
03683         curinfo.eff_color_path = normalize_color_path(v->reg[fbzColorPath].u);
03684         curinfo.eff_alpha_mode = normalize_alpha_mode(v->reg[alphaMode].u);
03685         curinfo.eff_fog_mode = normalize_fog_mode(v->reg[fogMode].u);
03686         curinfo.eff_fbz_mode = normalize_fbz_mode(v->reg[fbzMode].u);
03687         curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(v->tmu[0].reg[textureMode].u) : 0xffffffff;
03688         curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(v->tmu[1].reg[textureMode].u) : 0xffffffff;
03689 
03690         /* compute the hash */
03691         hash = compute_raster_hash(&curinfo);
03692 
03693         /* find the appropriate hash entry */
03694         for (info = v->raster_hash[hash]; info; prev = info, info = info->next)
03695                 if (info->eff_color_path == curinfo.eff_color_path &&
03696                         info->eff_alpha_mode == curinfo.eff_alpha_mode &&
03697                         info->eff_fog_mode == curinfo.eff_fog_mode &&
03698                         info->eff_fbz_mode == curinfo.eff_fbz_mode &&
03699                         info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 &&
03700                         info->eff_tex_mode_1 == curinfo.eff_tex_mode_1)
03701                 {
03702                         /* got it, move us to the head of the list */
03703                         if (prev)
03704                         {
03705                                 prev->next = info->next;
03706                                 info->next = v->raster_hash[hash];
03707                                 v->raster_hash[hash] = info;
03708                         }
03709 
03710                         /* return the result */
03711                         return info;
03712                 }
03713 
03714         /* generate a new one using the generic entry */
03715         curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu;
03716         curinfo.is_generic = true;
03717         curinfo.display = 0;
03718         curinfo.polys = 0;
03719         curinfo.hits = 0;
03720         curinfo.next = 0;
03721         curinfo.shader_ready = false;
03722 
03723         return add_rasterizer(v, &curinfo);
03724 }
03725 
03726 
03727 /***************************************************************************
03728     GENERIC RASTERIZERS
03729 ***************************************************************************/
03730 
03731 /*-------------------------------------------------
03732     raster_fastfill - per-scanline
03733     implementation of the 'fastfill' command
03734 -------------------------------------------------*/
03735 
03736 static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata)
03737 {
03738         const poly_extra_data *extra = (const poly_extra_data *)extradata;
03739         voodoo_state *v = extra->state;
03740         stats_block *stats = &v->thread_stats[0];
03741         INT32 startx = extent->startx;
03742         INT32 stopx = extent->stopx;
03743         int scry, x;
03744 
03745         /* determine the screen Y */
03746         scry = y;
03747         if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u))
03748                 scry = ((int)v->fbi.yorigin - y) & 0x3ff;
03749 
03750         /* fill this RGB row */
03751         if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u))
03752         {
03753                 const UINT16 *ditherow = &extra->dither[(y & 3) * 4];
03754                 UINT64 expanded = *(UINT64 *)ditherow;
03755                 UINT16 *dest = (UINT16 *)destbase + ((uintptr_t)((long)scry * (long)v->fbi.rowpixels));
03756 
03757                 for (x = startx; x < stopx && (x & 3) != 0; x++)
03758                         dest[x] = ditherow[x & 3];
03759                 for ( ; x < (stopx & ~3); x += 4)
03760                         *(UINT64 *)&dest[x] = expanded;
03761                 for ( ; x < stopx; x++)
03762                         dest[x] = ditherow[x & 3];
03763                 stats->pixels_out += stopx - startx;
03764         }
03765 
03766         /* fill this dest buffer row */
03767         if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != (UINT32)(~0))
03768         {
03769                 UINT16 color = (UINT16)(v->reg[zaColor].u & 0xffff);
03770                 UINT64 expanded = ((UINT64)color << 48ull) | ((UINT64)color << 32ull) | ((UINT64)color << 16ull) | (UINT64)color;
03771                 UINT16 *dest = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + ((uintptr_t)((long)scry * (long)v->fbi.rowpixels));
03772 
03773                 if ((unsigned long)((long)v->fbi.auxoffs + 2l * ((long)scry * (long)v->fbi.rowpixels + (long)stopx)) >= v->fbi.mask) {
03774                         stopx = ((long)v->fbi.mask - (long)v->fbi.auxoffs) / 2l - (long)scry * (long)v->fbi.rowpixels;
03775                         if ((stopx < 0) || (stopx < startx)) return;
03776                 }
03777 
03778                 for (x = startx; x < stopx && (x & 3) != 0; x++)
03779                         dest[x] = color;
03780                 for ( ; x < (stopx & ~3); x += 4)
03781                         *(UINT64 *)&dest[x] = expanded;
03782                 for ( ; x < stopx; x++)
03783                         dest[x] = color;
03784         }
03785 }
03786 
03787 
03788 void voodoo_vblank_flush(void) {
03789         if (v->ogl)
03790                 voodoo_ogl_vblank_flush();
03791         v->fbi.vblank_flush_pending=false;
03792 }
03793 
03794 void voodoo_set_window(void) {
03795         if (v->ogl && v->active) {
03796                 voodoo_ogl_set_window(v);
03797         }
03798 }
03799 
03800 void voodoo_leave(void) {
03801         if (v->ogl) {
03802 #if C_OPENGL
03803                 voodoo_ogl_leave(true);
03804 #endif
03805         }
03806         v->active = false;
03807 }
03808 
03809 void voodoo_activate(void) {
03810         v->active = true;
03811 
03812         if (v->ogl) {
03813                 if (voodoo_ogl_init(v)) {
03814                         voodoo_ogl_clear();
03815                 } else {
03816                         v->ogl = false;
03817                         LOG_MSG("VOODOO: acceleration disabled");
03818                 }
03819         }
03820 }
03821 
03822 void voodoo_update_dimensions(void) {
03823         v->ogl_dimchange = false;
03824 
03825         if (v->ogl) {
03826 #if C_OPENGL
03827                 voodoo_ogl_update_dimensions();
03828 #endif
03829         }
03830 }