DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_interface.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  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 along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 Bit8u Voodoo_PageHandler::readb(PhysPt addr) {
00042     (void)addr;//UNUSED
00043 //      LOG_MSG("voodoo readb at %x",addr);
00044         return (Bit8u)-1;
00045 }
00046 void Voodoo_PageHandler::writeb(PhysPt addr,Bit8u val) {
00047     (void)addr;//UNUSED
00048     (void)val;//UNUSED
00049 //      LOG_MSG("voodoo writeb at %x",addr);
00050 }
00051 
00052 Bit16u Voodoo_PageHandler::readw(PhysPt addr) {
00053         addr = PAGING_GetPhysicalAddress(addr);
00054     if (addr&1) {
00055         LOG_MSG("voodoo readw unaligned");
00056         return (Bit16u)-1;
00057     }
00058 
00059         Bit32u retval = voodoo_r((addr>>2)&0x3FFFFF);
00060         if (addr&3)
00061                 retval >>= 16;
00062         else
00063                 retval &= 0xffff;
00064 
00065         return (Bit16u)retval;
00066 }
00067 
00068 void Voodoo_PageHandler::writew(PhysPt addr,Bit16u val) {
00069         addr = PAGING_GetPhysicalAddress(addr);
00070         if (addr&1u) {
00071         LOG_MSG("voodoo writew unaligned");
00072         return;
00073     }
00074 
00075         if (addr&3u)
00076                 voodoo_w((addr>>2u)&0x3FFFFFu,(UINT32)(val<<16u),0xffff0000u);
00077         else
00078                 voodoo_w((addr>>2u)&0x3FFFFFu,val,0x0000ffffu);
00079 }
00080 
00081 Bit32u Voodoo_PageHandler::readd(PhysPt addr) {
00082         addr = PAGING_GetPhysicalAddress(addr);
00083         if (!(addr&3)) {
00084                 return voodoo_r((addr>>2)&0x3FFFFF);
00085         } else {
00086                 if (!(addr&1)) {
00087                         Bit32u low = voodoo_r((addr>>2)&0x3FFFFF);
00088                         Bit32u high = voodoo_r(((addr>>2)+1)&0x3FFFFF);
00089                         return (low>>16) | (high<<16);
00090                 } else {
00091                         LOG_MSG("voodoo readd unaligned");
00092                 }
00093         }
00094         return 0xffffffff;
00095 }
00096 
00097 void Voodoo_PageHandler::writed(PhysPt addr,Bit32u val) {
00098         addr = PAGING_GetPhysicalAddress(addr);
00099         if (!(addr&3)) {
00100                 voodoo_w((addr>>2)&0x3FFFFF,val,0xffffffff);
00101         } else {
00102                 if (!(addr&1)) {
00103                         voodoo_w((addr>>2)&0x3FFFFF,val<<16,0xffff0000);
00104                         voodoo_w(((addr>>2)+1)&0x3FFFFF,val>>16,0x0000ffff);
00105                 } else {
00106                         Bit32u val1 = voodoo_r((addr>>2)&0x3FFFFF);
00107                         Bit32u val2 = voodoo_r(((addr>>2)+1)&0x3FFFFF);
00108                         if ((addr&3)==1) {
00109                                 val1 = (val1&0xffffff) | ((val&0xff)<<24);
00110                                 val2 = (val2&0xff000000) | (val>>8);
00111                         } else if ((addr&3)==3) {
00112                                 val1 = (val1&0xff) | ((val&0xffffff)<<8);
00113                                 val2 = (val2&0xffffff00) | (val>>24);
00114                         } else E_Exit("???");
00115                         voodoo_w((addr>>2)&0x3FFFFF,val1,0xffffffff);
00116                         voodoo_w(((addr>>2)+1)&0x3FFFFF,val2,0xffffffff);
00117                 }
00118         }
00119 }
00120 
00121 
00122 static void Voodoo_VerticalTimer(Bitu /*val*/) {
00123         vdraw.frame_start = PIC_FullIndex();
00124         PIC_AddEvent( Voodoo_VerticalTimer, vdraw.vfreq );
00125 
00126         if (v->fbi.vblank_flush_pending) {
00127                 voodoo_vblank_flush();
00128                 if (GFX_LazyFullscreenRequested()) {
00129                         v->ogl_dimchange = true;
00130                 }
00131         }
00132 
00133         if (!v->ogl) {
00134                 if (!RENDER_StartUpdate()) return; // frameskip
00135 
00136                 rectangle r;
00137                 r.min_x = r.min_y = 0;
00138                 r.max_x = (int)v->fbi.width;
00139                 r.max_y = (int)v->fbi.height;
00140 
00141                 // draw all lines at once
00142                 Bit16u *viewbuf = (Bit16u *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]);
00143                 for(Bitu i = 0; i < v->fbi.height; i++) {
00144                         RENDER_DrawLine((Bit8u*) viewbuf);
00145                         viewbuf += v->fbi.rowpixels;
00146                 }
00147                 RENDER_EndUpdate(false);
00148         } else {
00149                 // ???
00150                 voodoo_set_window();
00151         }
00152 }
00153 
00154 bool Voodoo_GetRetrace() {
00155         // TODO proper implementation
00156         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00157         double vfreq = vdraw.vfreq;
00158         if (vfreq <= 0.0) return false;
00159         if (v->clock_enabled && v->output_on) {
00160                 if ((time_in_frame/vfreq) > 0.95) return true;
00161         } else if (v->output_on) {
00162                 double rtime = time_in_frame/vfreq;
00163                 rtime = fmod(rtime, 1.0);
00164                 if (rtime > 0.95) return true;
00165         }
00166         return false;
00167 }
00168 
00169 double Voodoo_GetVRetracePosition() {
00170         // TODO proper implementation
00171         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00172         double vfreq = vdraw.vfreq;
00173         if (vfreq <= 0.0) return 0.0;
00174         if (v->clock_enabled && v->output_on) {
00175                 return time_in_frame/vfreq;
00176         } else if (v->output_on) {
00177                 double rtime = time_in_frame/vfreq;
00178                 rtime = fmod(rtime, 1.0);
00179                 return rtime;
00180         }
00181         return 0.0;
00182 }
00183 
00184 double Voodoo_GetHRetracePosition() {
00185         // TODO proper implementation
00186         double time_in_frame = PIC_FullIndex() - vdraw.frame_start;
00187         double hfreq = vdraw.vfreq*100.0;
00188         if (hfreq <= 0.0) return 0.0;
00189         if (v->clock_enabled && v->output_on) {
00190                 return time_in_frame/hfreq;
00191         } else if (v->output_on) {
00192                 double rtime = time_in_frame/hfreq;
00193                 rtime = fmod(rtime, 1.0);
00194                 return rtime;
00195         }
00196         return 0.0;
00197 }
00198 
00199 static void Voodoo_UpdateScreen(void) {
00200         // abort drawing
00201         RENDER_EndUpdate(true);
00202 
00203         if ((!v->clock_enabled || !v->output_on) && vdraw.override_on) {
00204                 // switching off
00205                 PIC_RemoveEvents(Voodoo_VerticalTimer);
00206                 voodoo_leave();
00207 
00208                 VGA_SetOverride(false);
00209                 vdraw.override_on=false;
00210         }
00211 
00212         if ((v->clock_enabled && v->output_on) && !vdraw.override_on) {
00213                 // switching on
00214                 PIC_RemoveEvents(Voodoo_VerticalTimer); // shouldn't be needed
00215                 
00216                 // TODO proper implementation of refresh rates and timings
00217                 vdraw.vfreq = 1000.0f/60.0f;
00218                 VGA_SetOverride(true);
00219                 vdraw.override_on=true;
00220 
00221                 vdraw.height=v->fbi.height;
00222 
00223                 voodoo_activate();
00224                 
00225                 if (v->ogl) {
00226                         v->ogl_dimchange = false;
00227                 } else {
00228                         RENDER_SetSize(v->fbi.width, v->fbi.height, 16, 1000.0f / vdraw.vfreq, 4.0/3.0);
00229                 }
00230 
00231                 Voodoo_VerticalTimer(0);
00232         }
00233 
00234         if ((v->clock_enabled && v->output_on) && v->ogl_dimchange) {
00235                 voodoo_update_dimensions();
00236         }
00237 
00238         vdraw.screen_update_requested = false;
00239 }
00240 
00241 static void Voodoo_CheckScreenUpdate(Bitu /*val*/) {
00242         vdraw.screen_update_pending = false;
00243         if (vdraw.screen_update_requested) {
00244                 vdraw.screen_update_pending = true;
00245                 Voodoo_UpdateScreen();
00246                 PIC_AddEvent(Voodoo_CheckScreenUpdate, 100.0f);
00247         }
00248 }
00249 
00250 void Voodoo_UpdateScreenStart() {
00251         vdraw.screen_update_requested = true;
00252         if (!vdraw.screen_update_pending) {
00253                 vdraw.screen_update_pending = true;
00254                 PIC_AddEvent(Voodoo_CheckScreenUpdate, 0.0f);
00255         }
00256 }
00257 
00258 void Voodoo_Output_Enable(bool enabled) {
00259         if (v->output_on != enabled) {
00260                 v->output_on = enabled;
00261                 Voodoo_UpdateScreenStart();
00262         }
00263 }
00264 
00265 void Voodoo_Initialize(Bits emulation_type, Bits card_type, bool max_voodoomem) {
00266         if ((emulation_type <= 0) || (emulation_type > 2)) return;
00267 
00268         int board = VOODOO_1;
00269         
00270         switch (card_type) {
00271                 case 1:
00272                         if (max_voodoomem) board = VOODOO_1_DTMU;
00273                         else board = VOODOO_1;
00274                         break;
00275                 case 2:
00276 //                      if (max_voodoomem) board = VOODOO_2_DTMU;
00277 //                      else
00278                                 board = VOODOO_2;
00279                         break;
00280                 default:
00281                         E_Exit("invalid voodoo card type specified");
00282                         break;
00283         }
00284 
00285         voodoo_pagehandler = new Voodoo_PageHandler(0);
00286 
00287         v = new voodoo_state;
00288         v->ogl = false;
00289         extern bool OpenGL_using(void);
00290         if (emulation_type == 2) v->ogl = OpenGL_using();
00291 
00292         LOG(LOG_VOODOO,LOG_DEBUG)("voodoo: ogl=%u",v->ogl);
00293 
00294         vdraw.vfreq = 1000.0f/60.0f;
00295 
00296         voodoo_init(board);
00297 }
00298 
00299 void Voodoo_Shut_Down() {
00300         voodoo_shutdown();
00301 
00302         if (v != NULL) {
00303                 delete v;
00304                 v = NULL;
00305         }
00306         if (voodoo_pagehandler != NULL) {
00307                 delete voodoo_pagehandler;
00308                 voodoo_pagehandler = NULL;
00309         }
00310 }
00311 
00312 void Voodoo_PCI_InitEnable(Bitu val) {
00313         v->pci.init_enable = (UINT32)val;
00314 }
00315 
00316 void Voodoo_PCI_Enable(bool enable) {
00317         v->clock_enabled = enable;
00318         CPU_Core_Dyn_X86_SaveDHFPUState();
00319         Voodoo_UpdateScreenStart();
00320         CPU_Core_Dyn_X86_RestoreDHFPUState();
00321 }
00322 
00323 PageHandler* Voodoo_GetPageHandler() {
00324         return voodoo_pagehandler;
00325 }
00326