DOSBox-X
|
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