2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(ddraw
);
21 static IDirectDraw
*lpddraw
= NULL
;
22 static IDirectDrawSurface
*lpddsurf
;
23 static IDirectDrawPalette
*lpddpal
;
24 static DDSURFACEDESC sdesc
;
25 static LONG vga_polling
,vga_refresh
;
26 static HANDLE poll_timer
;
28 typedef HRESULT
WINAPI (*DirectDrawCreateProc
)(LPGUID
,LPDIRECTDRAW
*,LPUNKNOWN
);
29 static DirectDrawCreateProc pDirectDrawCreate
;
31 typedef HWND
WINAPI (*CreateWindowExAProc
)(DWORD
,LPCSTR
,LPCSTR
,DWORD
,INT
,INT
, INT
,INT
,HWND
,HMENU
,HINSTANCE
,LPVOID
);
32 static CreateWindowExAProc pCreateWindowExA
;
34 static void VGA_DeinstallTimer(void)
37 SERVICE_Delete( poll_timer
);
42 static void VGA_InstallTimer(unsigned Rate
)
46 poll_timer
= SERVICE_AddTimer( Rate
, VGA_Poll
, 0 );
49 HANDLE
VGA_AlphaConsole(void)
51 /* this assumes that no Win32 redirection has taken place, but then again,
52 * only 16-bit apps are likely to use this part of Wine... */
53 return GetStdHandle(STD_OUTPUT_HANDLE
);
56 char*VGA_AlphaBuffer(void)
58 return DOSMEM_MapDosToLinear(0xb8000);
61 /*** GRAPHICS MODE ***/
63 int VGA_SetMode(unsigned Xres
,unsigned Yres
,unsigned Depth
)
68 if (lpddraw
) VGA_Exit();
70 if (!pDirectDrawCreate
)
72 HMODULE hmod
= LoadLibraryA( "ddraw.dll" );
73 if (hmod
) pDirectDrawCreate
= (DirectDrawCreateProc
)GetProcAddress( hmod
, "DirectDrawCreate" );
74 if (!pDirectDrawCreate
) {
75 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
79 if (!pCreateWindowExA
)
81 HMODULE hmod
= LoadLibraryA( "user32.dll" );
83 ERR("Can't load user32.dll.\n");
86 if (hmod
) pCreateWindowExA
= (CreateWindowExAProc
)GetProcAddress( hmod
, "CreateWindowExA" );
87 if (!pCreateWindowExA
) {
88 ERR("Can't lookup CreateWindowExA from user32.dll.\n");
92 res
= pDirectDrawCreate(NULL
,&lpddraw
,NULL
);
94 ERR("DirectDraw is not available (res = %lx)\n",res
);
97 hwnd
= pCreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP
|WS_BORDER
|WS_CAPTION
|WS_SYSMENU
,0,0,Xres
,Yres
,0,0,0,NULL
);
99 ERR("Failed to create user window.\n");
101 if ((res
=IDirectDraw_SetCooperativeLevel(lpddraw
,hwnd
,DDSCL_FULLSCREEN
|DDSCL_EXCLUSIVE
))) {
102 ERR("Could not set cooperative level to exclusive (%lx)\n",res
);
105 if ((res
=IDirectDraw_SetDisplayMode(lpddraw
,Xres
,Yres
,Depth
))) {
106 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",Xres
,Yres
,Depth
,res
);
107 IDirectDraw_Release(lpddraw
);
111 res
=IDirectDraw_CreatePalette(lpddraw
,DDPCAPS_8BIT
,NULL
,&lpddpal
,NULL
);
113 ERR("Could not create palette (res = %lx)\n",res
);
115 memset(&sdesc
,0,sizeof(sdesc
));
116 sdesc
.dwSize
=sizeof(sdesc
);
117 sdesc
.dwFlags
= DDSD_CAPS
;
118 sdesc
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
119 if (IDirectDraw_CreateSurface(lpddraw
,&sdesc
,&lpddsurf
,NULL
)||(!lpddsurf
)) {
120 ERR("DirectDraw surface is not available\n");
121 IDirectDraw_Release(lpddraw
);
125 FIXME("no default palette entries\n");
126 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
128 /* poll every 20ms (50fps should provide adequate responsiveness) */
129 VGA_InstallTimer(20);
134 int VGA_GetMode(unsigned*Height
,unsigned*Width
,unsigned*Depth
)
136 if (!lpddraw
) return 1;
137 if (!lpddsurf
) return 1;
138 if (Height
) *Height
=sdesc
.dwHeight
;
139 if (Width
) *Width
=sdesc
.dwWidth
;
140 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u1
.dwRGBBitCount
;
147 VGA_DeinstallTimer();
148 IDirectDrawSurface_SetPalette(lpddsurf
,NULL
);
149 IDirectDrawSurface_Release(lpddsurf
);
151 IDirectDrawPalette_Release(lpddpal
);
153 IDirectDraw_Release(lpddraw
);
158 void VGA_SetPalette(PALETTEENTRY
*pal
,int start
,int len
)
160 if (!lpddraw
) return;
161 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
164 void VGA_SetQuadPalette(RGBQUAD
*color
,int start
,int len
)
166 PALETTEENTRY pal
[256];
169 if (!lpddraw
) return;
170 for (c
=0; c
<len
; c
++) {
171 pal
[c
].peRed
=color
[c
].rgbRed
;
172 pal
[c
].peGreen
=color
[c
].rgbGreen
;
173 pal
[c
].peBlue
=color
[c
].rgbBlue
;
176 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
179 LPSTR
VGA_Lock(unsigned*Pitch
,unsigned*Height
,unsigned*Width
,unsigned*Depth
)
181 if (!lpddraw
) return NULL
;
182 if (!lpddsurf
) return NULL
;
183 if (IDirectDrawSurface_Lock(lpddsurf
,NULL
,&sdesc
,0,0)) {
184 ERR("could not lock surface!\n");
187 if (Pitch
) *Pitch
=sdesc
.u1
.lPitch
;
188 if (Height
) *Height
=sdesc
.dwHeight
;
189 if (Width
) *Width
=sdesc
.dwWidth
;
190 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u1
.dwRGBBitCount
;
191 return sdesc
.lpSurface
;
194 void VGA_Unlock(void)
196 IDirectDrawSurface_Unlock(lpddsurf
,sdesc
.lpSurface
);
201 int VGA_SetAlphaMode(unsigned Xres
,unsigned Yres
)
205 if (lpddraw
) VGA_Exit();
207 /* the xterm is slow, so refresh only every 200ms (5fps) */
208 VGA_InstallTimer(200);
212 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz
);
216 void VGA_GetAlphaMode(unsigned*Xres
,unsigned*Yres
)
218 CONSOLE_SCREEN_BUFFER_INFO info
;
219 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
220 if (Xres
) *Xres
=info
.dwSize
.X
;
221 if (Yres
) *Yres
=info
.dwSize
.Y
;
224 void VGA_SetCursorPos(unsigned X
,unsigned Y
)
230 SetConsoleCursorPosition(VGA_AlphaConsole(),pos
);
233 void VGA_GetCursorPos(unsigned*X
,unsigned*Y
)
235 CONSOLE_SCREEN_BUFFER_INFO info
;
236 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
237 if (X
) *X
=info
.dwCursorPosition
.X
;
238 if (Y
) *Y
=info
.dwCursorPosition
.Y
;
241 void VGA_WriteChars(unsigned X
,unsigned Y
,unsigned ch
,int attr
,int count
)
246 VGA_GetAlphaMode(&XR
, &YR
);
247 dat
= VGA_AlphaBuffer() + ((XR
*Y
+ X
) * 2);
248 /* FIXME: also call WriteConsoleOutputA, for better responsiveness */
251 if (attr
>=0) *dat
= attr
;
258 void CALLBACK
VGA_Poll( ULONG_PTR arg
)
261 unsigned int Pitch
,Height
,Width
,Y
,X
;
264 if (!InterlockedExchangeAdd(&vga_polling
, 1)) {
265 /* FIXME: optimize by doing this only if the data has actually changed
266 * (in a way similar to DIBSection, perhaps) */
269 surf
= VGA_Lock(&Pitch
,&Height
,&Width
,NULL
);
271 dat
= DOSMEM_MapDosToLinear(0xa0000);
272 /* copy from virtual VGA frame buffer to DirectDraw surface */
273 for (Y
=0; Y
<Height
; Y
++,surf
+=Pitch
,dat
+=Width
) {
274 memcpy(surf
,dat
,Width
);
275 /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
283 HANDLE con
= VGA_AlphaConsole();
285 VGA_GetAlphaMode(&Width
,&Height
);
286 dat
= VGA_AlphaBuffer();
287 siz
.X
= 80; siz
.Y
= 1;
288 off
.X
= 0; off
.Y
= 0;
289 /* copy from virtual VGA frame buffer to console */
290 for (Y
=0; Y
<Height
; Y
++) {
291 dest
.Top
=Y
; dest
.Bottom
=Y
;
292 for (X
=0; X
<Width
; X
++) {
293 ch
[X
].Char
.AsciiChar
= *dat
++;
294 /* WriteConsoleOutputA doesn't like "dead" chars */
295 if (ch
[X
].Char
.AsciiChar
== '\0')
296 ch
[X
].Char
.AsciiChar
= ' ';
297 ch
[X
].Attributes
= *dat
++;
299 dest
.Left
=0; dest
.Right
=Width
+1;
300 WriteConsoleOutputA(con
, ch
, siz
, off
, &dest
);
305 InterlockedDecrement(&vga_polling
);
308 static BYTE palreg
,palcnt
;
309 static PALETTEENTRY paldat
;
311 void VGA_ioport_out( WORD port
, BYTE val
)
315 palreg
=val
; palcnt
=0; break;
317 ((BYTE
*)&paldat
)[palcnt
++]=val
<< 2;
319 VGA_SetPalette(&paldat
,palreg
++,1);
326 BYTE
VGA_ioport_in( WORD port
)
332 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
333 we need to fake the occurrence of the vertical refresh */
334 ret
=vga_refresh
?0x00:0x08;
346 VGA_DeinstallTimer();