2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
16 static IDirectDraw *lpddraw = NULL;
17 static IDirectDrawSurface *lpddsurf;
18 static IDirectDrawPalette *lpddpal;
19 static DDSURFACEDESC sdesc;
20 static WORD poll_timer;
21 static CRITICAL_SECTION vga_crit;
22 static int vga_polling,vga_refresh;
24 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
26 if (lpddraw) VGA_Exit();
28 DirectDrawCreate(NULL,&lpddraw,NULL);
30 ERR(ddraw,"DirectDraw is not available\n");
33 if (lpddraw->lpvtbl->fnSetDisplayMode(lpddraw,Xres,Yres,Depth)) {
34 ERR(ddraw,"DirectDraw does not support requested display mode\n");
35 lpddraw->lpvtbl->fnRelease(lpddraw);
39 lpddraw->lpvtbl->fnCreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
40 memset(&sdesc,0,sizeof(sdesc));
41 sdesc.dwSize=sizeof(sdesc);
42 sdesc.dwFlags = DDSD_CAPS;
43 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
44 if (lpddraw->lpvtbl->fnCreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
45 ERR(ddraw,"DirectDraw surface is not available\n");
46 lpddraw->lpvtbl->fnRelease(lpddraw);
51 InitializeCriticalSection(&vga_crit);
52 MakeCriticalSectionGlobal(&vga_crit);
53 /* poll every 20ms (50fps should provide adequate responsiveness) */
54 poll_timer = CreateSystemTimer( 20, VGA_Poll );
59 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
61 if (!lpddraw) return 1;
62 if (!lpddsurf) return 1;
63 if (Height) *Height=sdesc.dwHeight;
64 if (Width) *Width=sdesc.dwWidth;
65 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
72 SYSTEM_KillSystemTimer(poll_timer);
73 DeleteCriticalSection(&vga_crit);
74 lpddsurf->lpvtbl->fnRelease(lpddsurf);
76 lpddraw->lpvtbl->fnRelease(lpddraw);
81 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
84 lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
85 lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
88 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
90 PALETTEENTRY pal[256];
94 for (c=0; c<len; c++) {
95 pal[c].peRed =color[c].rgbRed;
96 pal[c].peGreen=color[c].rgbGreen;
97 pal[c].peBlue =color[c].rgbBlue;
100 lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
101 lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
104 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
106 if (!lpddraw) return NULL;
107 if (!lpddsurf) return NULL;
108 if (lpddsurf->lpvtbl->fnLock(lpddsurf,NULL,&sdesc,0,0)) {
109 ERR(ddraw,"could not lock surface!\n");
112 if (Pitch) *Pitch=sdesc.lPitch;
113 if (Height) *Height=sdesc.dwHeight;
114 if (Width) *Width=sdesc.dwWidth;
115 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
116 return sdesc.y.lpSurface;
119 void VGA_Unlock(void)
121 lpddsurf->lpvtbl->fnUnlock(lpddsurf,sdesc.y.lpSurface);
124 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
127 void VGA_Poll( WORD timer )
130 unsigned Pitch,Height,Width;
135 EnterCriticalSection(&vga_crit);
138 LeaveCriticalSection(&vga_crit);
139 /* FIXME: optimize by doing this only if the data has actually changed
140 * (in a way similar to DIBSection, perhaps) */
141 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
143 dat = DOSMEM_MapDosToLinear(0xa0000);
144 /* copy from virtual VGA frame buffer to DirectDraw surface */
145 for (Y=0; Y<Height; Y++,surf+=Pitch,dat+=Width) {
146 memcpy(surf,dat,Width);
147 /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
151 EnterCriticalSection(&vga_crit);
154 LeaveCriticalSection(&vga_crit);
157 static BYTE palreg,palcnt;
158 static PALETTEENTRY paldat;
160 void VGA_ioport_out( WORD port, BYTE val )
164 palreg=val; palcnt=0; break;
166 ((BYTE*)&paldat)[palcnt++]=val << 2;
168 VGA_SetPalette(&paldat,palreg,1);
175 BYTE VGA_ioport_in( WORD port )
181 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
182 we need to fake the occurrence of the vertical refresh */
184 ret=vga_refresh?0x00:0x08;