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