2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
18 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(ddraw
);
22 static IDirectDraw
*lpddraw
= NULL
;
23 static IDirectDrawSurface
*lpddsurf
;
24 static IDirectDrawPalette
*lpddpal
;
25 static DDSURFACEDESC sdesc
;
26 static LONG vga_polling
,vga_refresh
;
27 static HANDLE poll_timer
;
30 static int vga_height
;
33 typedef HRESULT
WINAPI (*DirectDrawCreateProc
)(LPGUID
,LPDIRECTDRAW
*,LPUNKNOWN
);
34 static DirectDrawCreateProc pDirectDrawCreate
;
36 static PALETTEENTRY vga_def_palette
[256]={
38 {0x00, 0x00, 0x00}, /* 0 - Black */
39 {0x00, 0x00, 0x80}, /* 1 - Blue */
40 {0x00, 0x80, 0x00}, /* 2 - Green */
41 {0x00, 0x80, 0x80}, /* 3 - Cyan */
42 {0x80, 0x00, 0x00}, /* 4 - Red */
43 {0x80, 0x00, 0x80}, /* 5 - Magenta */
44 {0x80, 0x80, 0x00}, /* 6 - Brown */
45 {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
46 {0x80, 0x80, 0x80}, /* 8 - Dark gray */
47 {0x00, 0x00, 0xFF}, /* 9 - Light blue */
48 {0x00, 0xFF, 0x00}, /* A - Light green */
49 {0x00, 0xFF, 0xFF}, /* B - Light cyan */
50 {0xFF, 0x00, 0x00}, /* C - Light red */
51 {0xFF, 0x00, 0xFF}, /* D - Light magenta */
52 {0xFF, 0xFF, 0x00}, /* E - Yellow */
53 {0xFF, 0xFF, 0xFF}, /* F - White */
54 {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
57 static void VGA_DeinstallTimer(void)
60 SERVICE_Delete( poll_timer
);
65 static void VGA_InstallTimer(unsigned Rate
)
69 poll_timer
= SERVICE_AddTimer( Rate
, VGA_Poll
, 0 );
72 HANDLE
VGA_AlphaConsole(void)
74 /* this assumes that no Win32 redirection has taken place, but then again,
75 * only 16-bit apps are likely to use this part of Wine... */
76 return GetStdHandle(STD_OUTPUT_HANDLE
);
79 char*VGA_AlphaBuffer(void)
81 return DOSMEM_MapDosToLinear(0xb8000);
84 /*** GRAPHICS MODE ***/
87 unsigned Xres
, Yres
, Depth
;
91 static void WINAPI
VGA_DoSetMode(ULONG_PTR arg
)
95 ModeSet
*par
= (ModeSet
*)arg
;
98 if (lpddraw
) VGA_Exit();
100 if (!pDirectDrawCreate
)
102 HMODULE hmod
= LoadLibraryA( "ddraw.dll" );
103 if (hmod
) pDirectDrawCreate
= (DirectDrawCreateProc
)GetProcAddress( hmod
, "DirectDrawCreate" );
104 if (!pDirectDrawCreate
) {
105 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
109 res
= pDirectDrawCreate(NULL
,&lpddraw
,NULL
);
111 ERR("DirectDraw is not available (res = %lx)\n",res
);
114 hwnd
= CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP
|WS_BORDER
|WS_CAPTION
|WS_SYSMENU
,0,0,par
->Xres
,par
->Yres
,0,0,0,NULL
);
116 ERR("Failed to create user window.\n");
118 if ((res
=IDirectDraw_SetCooperativeLevel(lpddraw
,hwnd
,DDSCL_FULLSCREEN
|DDSCL_EXCLUSIVE
))) {
119 ERR("Could not set cooperative level to exclusive (%lx)\n",res
);
122 if ((res
=IDirectDraw_SetDisplayMode(lpddraw
,par
->Xres
,par
->Yres
,par
->Depth
))) {
123 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par
->Xres
,par
->Yres
,par
->Depth
,res
);
124 IDirectDraw_Release(lpddraw
);
129 res
=IDirectDraw_CreatePalette(lpddraw
,DDPCAPS_8BIT
,NULL
,&lpddpal
,NULL
);
131 ERR("Could not create palette (res = %lx)\n",res
);
132 IDirectDraw_Release(lpddraw
);
136 if ((res
=IDirectDrawPalette_SetEntries(lpddpal
,0,0,256,vga_def_palette
))) {
137 ERR("Could not set default palette entries (res = %lx)\n", res
);
140 memset(&sdesc
,0,sizeof(sdesc
));
141 sdesc
.dwSize
=sizeof(sdesc
);
142 sdesc
.dwFlags
= DDSD_CAPS
;
143 sdesc
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
144 if (IDirectDraw_CreateSurface(lpddraw
,&sdesc
,&lpddsurf
,NULL
)||(!lpddsurf
)) {
145 ERR("DirectDraw surface is not available\n");
146 IDirectDraw_Release(lpddraw
);
150 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
152 /* poll every 20ms (50fps should provide adequate responsiveness) */
153 VGA_InstallTimer(20);
159 int VGA_SetMode(unsigned Xres
,unsigned Yres
,unsigned Depth
)
167 if(Xres
>= 640 || Yres
>= 480) {
175 par
.Depth
= (Depth
< 8) ? 8 : Depth
;
177 MZ_RunInThread(VGA_DoSetMode
, (ULONG_PTR
)&par
);
181 int VGA_GetMode(unsigned*Height
,unsigned*Width
,unsigned*Depth
)
183 if (!lpddraw
) return 1;
184 if (!lpddsurf
) return 1;
185 if (Height
) *Height
=sdesc
.dwHeight
;
186 if (Width
) *Width
=sdesc
.dwWidth
;
187 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u1
.dwRGBBitCount
;
191 static void WINAPI
VGA_DoExit(ULONG_PTR arg
)
193 VGA_DeinstallTimer();
194 IDirectDrawSurface_SetPalette(lpddsurf
,NULL
);
195 IDirectDrawSurface_Release(lpddsurf
);
197 IDirectDrawPalette_Release(lpddpal
);
199 IDirectDraw_Release(lpddraw
);
205 if (lpddraw
) MZ_RunInThread(VGA_DoExit
, 0);
208 void VGA_SetPalette(PALETTEENTRY
*pal
,int start
,int len
)
210 if (!lpddraw
) return;
211 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
214 void VGA_SetQuadPalette(RGBQUAD
*color
,int start
,int len
)
216 PALETTEENTRY pal
[256];
219 if (!lpddraw
) return;
220 for (c
=0; c
<len
; c
++) {
221 pal
[c
].peRed
=color
[c
].rgbRed
;
222 pal
[c
].peGreen
=color
[c
].rgbGreen
;
223 pal
[c
].peBlue
=color
[c
].rgbBlue
;
226 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
229 LPSTR
VGA_Lock(unsigned*Pitch
,unsigned*Height
,unsigned*Width
,unsigned*Depth
)
231 if (!lpddraw
) return NULL
;
232 if (!lpddsurf
) return NULL
;
233 if (IDirectDrawSurface_Lock(lpddsurf
,NULL
,&sdesc
,0,0)) {
234 ERR("could not lock surface!\n");
237 if (Pitch
) *Pitch
=sdesc
.u1
.lPitch
;
238 if (Height
) *Height
=sdesc
.dwHeight
;
239 if (Width
) *Width
=sdesc
.dwWidth
;
240 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.u1
.dwRGBBitCount
;
241 return sdesc
.lpSurface
;
244 void VGA_Unlock(void)
246 IDirectDrawSurface_Unlock(lpddsurf
,sdesc
.lpSurface
);
251 int VGA_SetAlphaMode(unsigned Xres
,unsigned Yres
)
255 if (lpddraw
) VGA_Exit();
257 /* the xterm is slow, so refresh only every 200ms (5fps) */
258 VGA_InstallTimer(200);
262 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz
);
266 void VGA_GetAlphaMode(unsigned*Xres
,unsigned*Yres
)
268 CONSOLE_SCREEN_BUFFER_INFO info
;
269 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
270 if (Xres
) *Xres
=info
.dwSize
.X
;
271 if (Yres
) *Yres
=info
.dwSize
.Y
;
274 void VGA_SetCursorPos(unsigned X
,unsigned Y
)
278 if (!poll_timer
) VGA_SetAlphaMode(80, 25);
281 SetConsoleCursorPosition(VGA_AlphaConsole(),pos
);
284 void VGA_GetCursorPos(unsigned*X
,unsigned*Y
)
286 CONSOLE_SCREEN_BUFFER_INFO info
;
287 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info
);
288 if (X
) *X
=info
.dwCursorPosition
.X
;
289 if (Y
) *Y
=info
.dwCursorPosition
.Y
;
292 void VGA_WriteChars(unsigned X
,unsigned Y
,unsigned ch
,int attr
,int count
)
297 VGA_GetAlphaMode(&XR
, &YR
);
298 dat
= VGA_AlphaBuffer() + ((XR
*Y
+ X
) * 2);
299 /* FIXME: also call WriteConsoleOutputA, for better responsiveness */
302 if (attr
>=0) *dat
= attr
;
309 static void VGA_Poll_Graphics(void)
311 unsigned int Pitch
, Height
, Width
, X
, Y
;
313 char *dat
= DOSMEM_MapDosToLinear(0xa0000);
315 surf
= VGA_Lock(&Pitch
,&Height
,&Width
,NULL
);
318 if(vga_width
== 320 && vga_depth
<= 4)
319 for (Y
=0; Y
<vga_height
; Y
++,surf
+=Pitch
*2,dat
+=vga_width
/8) {
320 for(X
=0; X
<vga_width
; X
+=8) {
324 int b0
= (dat
[offset
] >> Z
) & 0x1;
326 surf
[(X
+index
)*2] = b0
;
327 surf
[(X
+index
)*2+1] = b0
;
328 surf
[(X
+index
)*2+Pitch
] = b0
;
329 surf
[(X
+index
)*2+Pitch
+1] = b0
;
334 if(vga_width
== 320 && vga_depth
== 8)
335 for (Y
=0; Y
<vga_height
; Y
++,surf
+=Pitch
*2,dat
+=vga_width
) {
336 for(X
=0; X
<vga_width
; X
++) {
340 surf
[X
*2+Pitch
] = b0
;
341 surf
[X
*2+Pitch
+1] = b0
;
346 for (Y
=0; Y
<vga_height
; Y
++,surf
+=Pitch
,dat
+=vga_width
/8) {
347 for(X
=0; X
<vga_width
; X
+=8) {
351 int b0
= (dat
[offset
] >> Z
) & 0x1;
362 void CALLBACK
VGA_Poll( ULONG_PTR arg
)
365 unsigned int Height
,Width
,Y
,X
;
367 if (!InterlockedExchangeAdd(&vga_polling
, 1)) {
368 /* FIXME: optimize by doing this only if the data has actually changed
369 * (in a way similar to DIBSection, perhaps) */
377 HANDLE con
= VGA_AlphaConsole();
379 VGA_GetAlphaMode(&Width
,&Height
);
380 dat
= VGA_AlphaBuffer();
381 siz
.X
= 80; siz
.Y
= 1;
382 off
.X
= 0; off
.Y
= 0;
383 /* copy from virtual VGA frame buffer to console */
384 for (Y
=0; Y
<Height
; Y
++) {
385 dest
.Top
=Y
; dest
.Bottom
=Y
;
386 for (X
=0; X
<Width
; X
++) {
387 ch
[X
].Char
.AsciiChar
= *dat
++;
388 /* WriteConsoleOutputA doesn't like "dead" chars */
389 if (ch
[X
].Char
.AsciiChar
== '\0')
390 ch
[X
].Char
.AsciiChar
= ' ';
391 ch
[X
].Attributes
= *dat
++;
393 dest
.Left
=0; dest
.Right
=Width
+1;
394 WriteConsoleOutputA(con
, ch
, siz
, off
, &dest
);
399 InterlockedDecrement(&vga_polling
);
402 static BYTE palreg
,palcnt
;
403 static PALETTEENTRY paldat
;
405 void VGA_ioport_out( WORD port
, BYTE val
)
409 palreg
=val
; palcnt
=0; break;
411 ((BYTE
*)&paldat
)[palcnt
++]=val
<< 2;
413 VGA_SetPalette(&paldat
,palreg
++,1);
420 BYTE
VGA_ioport_in( WORD port
)
426 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
427 we need to fake the occurrence of the vertical refresh */
428 ret
=vga_refresh
?0x00:0x08;
440 VGA_DeinstallTimer();