DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_interface.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <stdlib.h>
00021 #include <math.h>
00022 
00023 #include "dosbox.h"
00024 #include "cross.h"
00025 
00026 #include "vga.h"
00027 #include "pic.h"
00028 #include "paging.h"
00029 #include "render.h"
00030 
00031 #include "voodoo_interface.h"
00032 #include "voodoo_emu.h"
00033 
00034 
00035 static voodoo_draw vdraw;
00036 
00037 
00038 Voodoo_PageHandler * voodoo_pagehandler;
00039 
00040 
00041 Bitu Voodoo_PageHandler::readb(PhysPt addr) {
00042     (void)addr;//UNUSED
00043 //      LOG_MSG("voodoo readb at %x",addr);
00044         return (Bitu)-1;
00045 }
00046 void Voodoo_PageHandler::writeb(PhysPt addr,Bitu val) {
00047     (void)addr;//UNUSED
00048     (void)val;//UNUSED
00049 //      LOG_MSG("voodoo writeb at %x",addr);
00050 }
00051 
00052 Bitu Voodoo_PageHandler::readw(PhysPt addr) {
00053         addr = PAGING_GetPhysicalAddress(addr);
00054     if (addr&1) {
00055         LOG_MSG("voodoo readw unaligned");
00056         return (Bitu)-1;
00057     }
00058 
00059         Bitu retval=voodoo_r((addr>>2)&0x3FFFFF);
00060         if (addr&3)
00061                 retval >>= 16;
00062         else
00063                 retval &= 0xffff;
00064         return retval;
00065 }
00066 
00067 void Voodoo_PageHandler::writew(PhysPt addr,Bitu val) {
00068         addr = PAGING_GetPhysicalAddress(addr);
00069         if (addr&1) {
00070         LOG_MSG("voodoo writew unaligned");
00071         return;
00072     }
00073 
00074         if (addr&3)
00075                 voodoo_w((addr>>2)&0x3FFFFF,val<<16,0xffff0000);
00076         else
00077                 voodoo_w((addr>>2)&0x3FFFFF,val,0x0000ffff);
00078 }
00079 
00080 Bitu Voodoo_PageHandler::readd(PhysPt addr) {
00081         addr = PAGING_GetPhysicalAddress(addr);
00082         if (!(addr&3)) {
00083                 return voodoo_r((addr>>2)&0x3FFFFF);
00084         } else {
00085                 if (!(addr&1)) {
00086                         Bitu low = voodoo_r((addr>>2)&0x3FFFFF);
00087                         Bitu high = voodoo_r(((addr>>2)+1)&0x3FFFFF);
00088                         return (low>>16) | (high<<16);
00089                 } else {
00090                         LOG_MSG("voodoo readd unaligned");
00091                 }
00092         }
00093         return 0xffffffff;
00094 }
00095 
00096 void Voodoo_PageHandler::writed(PhysPt addr,Bitu val) {
00097         addr = PAGING_GetPhysicalAddress(addr);
00098         if (!(addr&3)) {
00099                 voodoo_w((addr>>2)&0x3FFFFF,val,0xffffffff);
00100         } else {
00101                 if (!(addr&1)) {
00102                         voodoo_w((addr>>2)&0x3FFFFF,val<<16,0xffff0000);
00103                         voodoo_w(((addr>>2)+1)&0x3FFFFF,val>>16,0x0000ffff);
00104                 } else {
00105                         Bit32u val1 = voodoo_r((addr>>2)&0x3FFFFF);
00106                         Bit32u val2 = voodoo_r(((addr>>2)+1)&0x3FFFFF);
00107                         if ((addr&3)==1) {
00108                                 val1 = (val1&0xffffff) | ((val&0xff)<<24);
00109                                 val2 = (val2&0xff000000) | (val>>8);
00110                         } else if ((addr&3)==3) {
00111                                 val1 = (val1&0xff) | ((val&0xffffff)<<8);
00112                                 val2 = (val2&0xffffff00) | (val>>24);
00113                         } else E_Exit("???");
00114                         voodoo_w((addr>>2)&0x3FFFFF,val1,0xffffffff);
00115                         voodoo_w(((addr>>2)+1)&0x3FFFFF,val2,0xffffffff);
00116                 }
00117         }
00118 }
00119 
00120 
00121 static void Voodoo_VerticalTimer(Bitu /*val*/) {
00122         vdraw.frame_start = PIC_FullIndex();
00123         PIC_AddEvent( Voodoo_VerticalTimer, vdraw.vfreq );
00124 
00125         if (v->fbi.vblank_flush_pending) {
00126                 voodoo_vblank_flush();
00127                 if (GFX_LazyFullscreenRequested()) {
00128                         v->ogl_dimchange = true;
00129                 }
00130         }
00131 
00132         if (!v->ogl) {
00133                 if (!RENDER_StartUpdate()) return; // frameskip
00134 
00135                 rectangle r;
00136                 r.min_x = r.min_y = 0;
00137                 r.max_x = (int)v->fbi.width;
00138                 r.max_y = (int)v->fbi.height;
00139 
00140                 // draw all lines at once
00141                 Bit16u *viewbuf = (Bit16u *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
00142                 for(Bitu i = 0; i < v->fbi.height; i++) {
00143                         RENDER_DrawLine((Bit8u*) viewbuf);
00144                         viewbuf += v->fbi.rowpixels;
00145                 }
00146                 RENDER_EndUpdate(false);
00147         } else {
00148                 // ???
00149                 voodoo_set_window();
00150         }
00151 }
00152 
00153 bool Voodoo_GetRetrace() {
00154         // TODO proper implementation
00155         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00156         double vfreq = vdraw.vfreq;
00157         if (vfreq <= 0.0) return false;
00158         if (v->clock_enabled && v->output_on) {
00159                 if ((time_in_frame/vfreq) > 0.95) return true;
00160         } else if (v->output_on) {
00161                 double rtime = time_in_frame/vfreq;
00162                 rtime = fmod(rtime, 1.0);
00163                 if (rtime > 0.95) return true;
00164         }
00165         return false;
00166 }
00167 
00168 double Voodoo_GetVRetracePosition() {
00169         // TODO proper implementation
00170         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00171         double vfreq = vdraw.vfreq;
00172         if (vfreq <= 0.0) return 0.0;
00173         if (v->clock_enabled && v->output_on) {
00174                 return time_in_frame/vfreq;
00175         } else if (v->output_on) {
00176                 double rtime = time_in_frame/vfreq;
00177                 rtime = fmod(rtime, 1.0);
00178                 return rtime;
00179         }
00180         return 0.0;
00181 }
00182 
00183 double Voodoo_GetHRetracePosition() {
00184         // TODO proper implementation
00185         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00186         double hfreq = vdraw.vfreq*100.0;
00187         if (hfreq <= 0.0) return 0.0;
00188         if (v->clock_enabled && v->output_on) {
00189                 return time_in_frame/hfreq;
00190         } else if (v->output_on) {
00191                 double rtime = time_in_frame/hfreq;
00192                 rtime = fmod(rtime, 1.0);
00193                 return rtime;
00194         }
00195         return 0.0;
00196 }
00197 
00198 static void Voodoo_UpdateScreen(void) {
00199         // abort drawing
00200         RENDER_EndUpdate(true);
00201 
00202         if ((!v->clock_enabled || !v->output_on) && vdraw.override_on) {
00203                 // switching off
00204                 PIC_RemoveEvents(Voodoo_VerticalTimer);
00205                 voodoo_leave();
00206 
00207                 VGA_SetOverride(false);
00208                 vdraw.override_on=false;
00209         }
00210 
00211         if ((v->clock_enabled && v->output_on) && !vdraw.override_on) {
00212                 // switching on
00213                 PIC_RemoveEvents(Voodoo_VerticalTimer); // shouldn't be needed
00214                 
00215                 // TODO proper implementation of refresh rates and timings
00216                 vdraw.vfreq = 1000.0f/60.0f;
00217                 VGA_SetOverride(true);
00218                 vdraw.override_on=true;
00219 
00220                 vdraw.height=v->fbi.height;
00221 
00222                 voodoo_activate();
00223                 
00224                 if (v->ogl) {
00225                         v->ogl_dimchange = false;
00226                 } else {
00227                         RENDER_SetSize(v->fbi.width, v->fbi.height, 16, vdraw.vfreq, 4.0/3.0);
00228                 }
00229 
00230                 Voodoo_VerticalTimer(0);
00231         }
00232 
00233         if ((v->clock_enabled && v->output_on) && v->ogl_dimchange) {
00234                 voodoo_update_dimensions();
00235         }
00236 
00237         vdraw.screen_update_requested = false;
00238 }
00239 
00240 static void Voodoo_CheckScreenUpdate(Bitu /*val*/) {
00241         vdraw.screen_update_pending = false;
00242         if (vdraw.screen_update_requested) {
00243                 vdraw.screen_update_pending = true;
00244                 Voodoo_UpdateScreen();
00245                 PIC_AddEvent(Voodoo_CheckScreenUpdate, 100.0f);
00246         }
00247 }
00248 
00249 void Voodoo_UpdateScreenStart() {
00250         vdraw.screen_update_requested = true;
00251         if (!vdraw.screen_update_pending) {
00252                 vdraw.screen_update_pending = true;
00253                 PIC_AddEvent(Voodoo_CheckScreenUpdate, 0.0f);
00254         }
00255 }
00256 
00257 void Voodoo_Output_Enable(bool enabled) {
00258         if (v->output_on != enabled) {
00259                 v->output_on = enabled;
00260                 Voodoo_UpdateScreenStart();
00261         }
00262 }
00263 
00264 void Voodoo_Initialize(Bits emulation_type, Bits card_type, bool max_voodoomem) {
00265         if ((emulation_type <= 0) || (emulation_type > 2)) return;
00266 
00267         int board = VOODOO_1;
00268         
00269         switch (card_type) {
00270                 case 1:
00271                         if (max_voodoomem) board = VOODOO_1_DTMU;
00272                         else board = VOODOO_1;
00273                         break;
00274                 case 2:
00275 //                      if (max_voodoomem) board = VOODOO_2_DTMU;
00276 //                      else
00277                                 board = VOODOO_2;
00278                         break;
00279                 default:
00280                         E_Exit("invalid voodoo card type specified");
00281                         break;
00282         }
00283 
00284         voodoo_pagehandler = new Voodoo_PageHandler(0);
00285 
00286         v = new voodoo_state;
00287         v->ogl = false;
00288         extern bool OpenGL_using(void);
00289         if (emulation_type == 2) v->ogl = OpenGL_using();
00290 
00291         LOG(LOG_VOODOO,LOG_DEBUG)("voodoo: ogl=%u",v->ogl);
00292 
00293         vdraw.vfreq = 1000.0f/60.0f;
00294 
00295         voodoo_init(board);
00296 }
00297 
00298 void Voodoo_Shut_Down() {
00299         voodoo_shutdown();
00300 
00301         if (v != NULL) {
00302                 delete v;
00303                 v = NULL;
00304         }
00305         if (voodoo_pagehandler != NULL) {
00306                 delete voodoo_pagehandler;
00307                 voodoo_pagehandler = NULL;
00308         }
00309 }
00310 
00311 void Voodoo_PCI_InitEnable(Bitu val) {
00312         v->pci.init_enable = val;
00313 }
00314 
00315 void Voodoo_PCI_Enable(bool enable) {
00316         v->clock_enabled = enable;
00317         CPU_Core_Dyn_X86_SaveDHFPUState();
00318         Voodoo_UpdateScreenStart();
00319         CPU_Core_Dyn_X86_RestoreDHFPUState();
00320 }
00321 
00322 PageHandler* Voodoo_GetPageHandler() {
00323         return voodoo_pagehandler;
00324 }
00325