2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
15 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(ddraw
)
19 static IDirectDraw
*lpddraw
= NULL
;
20 static IDirectDrawSurface
*lpddsurf
;
21 static IDirectDrawPalette
*lpddpal
;
22 static DDSURFACEDESC sdesc
;
23 static LONG vga_polling
,vga_refresh
;
24 static HANDLE poll_timer
;
26 static HRESULT
WINAPI (*pDirectDrawCreate
)(LPGUID
,LPDIRECTDRAW
*,LPUNKNOWN
);
28 static void VGA_DeinstallTimer(void)
31 SERVICE_Delete( poll_timer
);
36 static void VGA_InstallTimer(unsigned Rate
)
40 poll_timer
= SERVICE_AddTimer( Rate
, VGA_Poll
, 0 );
43 HANDLE
VGA_AlphaConsole(void)
45 /* this assumes that no Win32 redirection has taken place, but then again,
46 * only 16-bit apps are likely to use this part of Wine... */
47 return GetStdHandle(STD_OUTPUT_HANDLE
);
50 /*** GRAPHICS MODE ***/
52 int VGA_SetMode(unsigned Xres
,unsigned Yres
,unsigned Depth
)
54 if (lpddraw
) VGA_Exit();
56 if (!pDirectDrawCreate
)
58 HMODULE hmod
= LoadLibraryA( "ddraw.dll" );
59 if (hmod
) pDirectDrawCreate
= GetProcAddress( hmod
, "DirectDrawCreate" );
61 if (pDirectDrawCreate
) pDirectDrawCreate(NULL
,&lpddraw
,NULL
);
63 ERR("DirectDraw is not available\n");
66 if (IDirectDraw_SetDisplayMode(lpddraw
,Xres
,Yres
,Depth
)) {
67 ERR("DirectDraw does not support requested display mode\n");
68 IDirectDraw_Release(lpddraw
);
72 IDirectDraw_CreatePalette(lpddraw
,DDPCAPS_8BIT
,NULL
,&lpddpal
,NULL
);
73 memset(&sdesc
,0,sizeof(sdesc
));
74 sdesc
.dwSize
=sizeof(sdesc
);
75 sdesc
.dwFlags
= DDSD_CAPS
;
76 sdesc
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
77 if (IDirectDraw_CreateSurface(lpddraw
,&sdesc
,&lpddsurf
,NULL
)||(!lpddsurf
)) {
78 ERR("DirectDraw surface is not available\n");
79 IDirectDraw_Release(lpddraw
);
84 /* poll every 20ms (50fps should provide adequate responsiveness) */
85 VGA_InstallTimer(20000);
90 int VGA_GetMode(unsigned*Height
,unsigned*Width
,unsigned*Depth
)
92 if (!lpddraw
) return 1;
93 if (!lpddsurf
) return 1;
94 if (Height
) *Height
=sdesc
.dwHeight
;
95 if (Width
) *Width
=sdesc
.dwWidth
;
96 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u
.dwRGBBitCount
;
103 VGA_DeinstallTimer();
104 IDirectDrawSurface_Release(lpddsurf
);
106 IDirectDraw_Release(lpddraw
);
111 void VGA_SetPalette(PALETTEENTRY
*pal
,int start
,int len
)
113 if (!lpddraw
) return;
114 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
115 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
118 void VGA_SetQuadPalette(RGBQUAD
*color
,int start
,int len
)
120 PALETTEENTRY pal
[256];
123 if (!lpddraw
) return;
124 for (c
=0; c
<len
; c
++) {
125 pal
[c
].peRed
=color
[c
].rgbRed
;
126 pal
[c
].peGreen
=color
[c
].rgbGreen
;
127 pal
[c
].peBlue
=color
[c
].rgbBlue
;
130 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
131 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
134 LPSTR
VGA_Lock(unsigned*Pitch
,unsigned*Height
,unsigned*Width
,unsigned*Depth
)
136 if (!lpddraw
) return NULL
;
137 if (!lpddsurf
) return NULL
;
138 if (IDirectDrawSurface_Lock(lpddsurf
,NULL
,&sdesc
,0,0)) {
139 ERR("could not lock surface!\n");
142 if (Pitch
) *Pitch
=sdesc
.lPitch
;
143 if (Height
) *Height
=sdesc
.dwHeight
;
144 if (Width
) *Width
=sdesc
.dwWidth
;
145 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u
.dwRGBBitCount
;
146 return sdesc
.u1
.lpSurface
;
149 void VGA_Unlock(void)
151 IDirectDrawSurface_Unlock(lpddsurf
,sdesc
.u1
.lpSurface
);
156 int VGA_SetAlphaMode(unsigned Xres
,unsigned Yres
)
160 if (lpddraw
) VGA_Exit();
162 /* the xterm is slow, so refresh only every 200ms (5fps) */
163 VGA_InstallTimer(200000);
167 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz
);
171 void VGA_GetAlphaMode(unsigned*Xres
,unsigned*Yres
)
173 CONSOLE_SCREEN_BUFFER_INFO info
;
174 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
175 if (Xres
) *Xres
=info
.dwSize
.x
;
176 if (Yres
) *Yres
=info
.dwSize
.y
;
179 void VGA_SetCursorPos(unsigned X
,unsigned Y
)
185 SetConsoleCursorPosition(VGA_AlphaConsole(),pos
);
188 void VGA_GetCursorPos(unsigned*X
,unsigned*Y
)
190 CONSOLE_SCREEN_BUFFER_INFO info
;
191 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
192 if (X
) *X
=info
.dwCursorPosition
.x
;
193 if (Y
) *Y
=info
.dwCursorPosition
.y
;
198 void CALLBACK
VGA_Poll( ULONG_PTR arg
)
201 unsigned Pitch
,Height
,Width
;
205 if (!InterlockedExchangeAdd(&vga_polling
, 1)) {
206 /* FIXME: optimize by doing this only if the data has actually changed
207 * (in a way similar to DIBSection, perhaps) */
210 surf
= VGA_Lock(&Pitch
,&Height
,&Width
,NULL
);
212 dat
= DOSMEM_MapDosToLinear(0xa0000);
213 /* copy from virtual VGA frame buffer to DirectDraw surface */
214 for (Y
=0; Y
<Height
; Y
++,surf
+=Pitch
,dat
+=Width
) {
215 memcpy(surf
,dat
,Width
);
216 /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
224 HANDLE con
= VGA_AlphaConsole();
226 VGA_GetAlphaMode(&Width
,&Height
);
227 dat
= DOSMEM_MapDosToLinear(0xb8000);
228 siz
.x
= 80; siz
.y
= 1;
229 off
.x
= 0; off
.y
= 0;
230 /* copy from virtual VGA frame buffer to console */
231 for (Y
=0; Y
<Height
; Y
++) {
232 dest
.Top
=Y
; dest
.Bottom
=Y
;
233 for (X
=0; X
<Width
; X
++) {
234 ch
[X
].Char
.AsciiChar
= *dat
++;
235 ch
[X
].Attributes
= *dat
++;
237 dest
.Left
=0; dest
.Right
=Width
+1;
238 WriteConsoleOutputA(con
, ch
, siz
, off
, &dest
);
243 InterlockedDecrement(&vga_polling
);
246 static BYTE palreg
,palcnt
;
247 static PALETTEENTRY paldat
;
249 void VGA_ioport_out( WORD port
, BYTE val
)
253 palreg
=val
; palcnt
=0; break;
255 ((BYTE
*)&paldat
)[palcnt
++]=val
<< 2;
257 VGA_SetPalette(&paldat
,palreg
++,1);
264 BYTE
VGA_ioport_in( WORD port
)
270 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
271 we need to fake the occurrence of the vertical refresh */
272 ret
=vga_refresh
?0x00:0x08;
284 VGA_DeinstallTimer();