2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
11 #include "wine/winuser16.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 WORD poll_timer
;
24 static CRITICAL_SECTION vga_crit
;
25 static int vga_polling
,vga_refresh
;
27 int VGA_SetMode(unsigned Xres
,unsigned Yres
,unsigned Depth
)
29 if (lpddraw
) VGA_Exit();
31 DirectDrawCreate(NULL
,&lpddraw
,NULL
);
33 ERR(ddraw
,"DirectDraw is not available\n");
36 if (IDirectDraw_SetDisplayMode(lpddraw
,Xres
,Yres
,Depth
)) {
37 ERR(ddraw
,"DirectDraw does not support requested display mode\n");
38 IDirectDraw_Release(lpddraw
);
42 IDirectDraw_CreatePalette(lpddraw
,DDPCAPS_8BIT
,NULL
,&lpddpal
,NULL
);
43 memset(&sdesc
,0,sizeof(sdesc
));
44 sdesc
.dwSize
=sizeof(sdesc
);
45 sdesc
.dwFlags
= DDSD_CAPS
;
46 sdesc
.ddsCaps
.dwCaps
= DDSCAPS_PRIMARYSURFACE
;
47 if (IDirectDraw_CreateSurface(lpddraw
,&sdesc
,&lpddsurf
,NULL
)||(!lpddsurf
)) {
48 ERR(ddraw
,"DirectDraw surface is not available\n");
49 IDirectDraw_Release(lpddraw
);
54 InitializeCriticalSection(&vga_crit
);
55 MakeCriticalSectionGlobal(&vga_crit
);
56 /* poll every 20ms (50fps should provide adequate responsiveness) */
57 poll_timer
= CreateSystemTimer( 20, VGA_Poll
);
62 int VGA_GetMode(unsigned*Height
,unsigned*Width
,unsigned*Depth
)
64 if (!lpddraw
) return 1;
65 if (!lpddsurf
) return 1;
66 if (Height
) *Height
=sdesc
.dwHeight
;
67 if (Width
) *Width
=sdesc
.dwWidth
;
68 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.x
.dwRGBBitCount
;
75 SYSTEM_KillSystemTimer(poll_timer
);
76 DeleteCriticalSection(&vga_crit
);
77 IDirectDrawSurface_Release(lpddsurf
);
79 IDirectDraw_Release(lpddraw
);
84 void VGA_SetPalette(PALETTEENTRY
*pal
,int start
,int len
)
87 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
88 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
91 void VGA_SetQuadPalette(RGBQUAD
*color
,int start
,int len
)
93 PALETTEENTRY pal
[256];
97 for (c
=0; c
<len
; c
++) {
98 pal
[c
].peRed
=color
[c
].rgbRed
;
99 pal
[c
].peGreen
=color
[c
].rgbGreen
;
100 pal
[c
].peBlue
=color
[c
].rgbBlue
;
103 IDirectDrawPalette_SetEntries(lpddpal
,0,start
,len
,pal
);
104 IDirectDrawSurface_SetPalette(lpddsurf
,lpddpal
);
107 LPSTR
VGA_Lock(unsigned*Pitch
,unsigned*Height
,unsigned*Width
,unsigned*Depth
)
109 if (!lpddraw
) return NULL
;
110 if (!lpddsurf
) return NULL
;
111 if (IDirectDrawSurface_Lock(lpddsurf
,NULL
,&sdesc
,0,0)) {
112 ERR(ddraw
,"could not lock surface!\n");
115 if (Pitch
) *Pitch
=sdesc
.lPitch
;
116 if (Height
) *Height
=sdesc
.dwHeight
;
117 if (Width
) *Width
=sdesc
.dwWidth
;
118 if (Depth
) *Depth
=sdesc
.ddpfPixelFormat
.x
.dwRGBBitCount
;
119 return sdesc
.y
.lpSurface
;
122 void VGA_Unlock(void)
124 IDirectDrawSurface_Unlock(lpddsurf
,sdesc
.y
.lpSurface
);
127 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
130 void VGA_Poll( WORD timer
)
133 unsigned Pitch
,Height
,Width
;
138 EnterCriticalSection(&vga_crit
);
141 LeaveCriticalSection(&vga_crit
);
142 /* FIXME: optimize by doing this only if the data has actually changed
143 * (in a way similar to DIBSection, perhaps) */
144 surf
= VGA_Lock(&Pitch
,&Height
,&Width
,NULL
);
146 dat
= DOSMEM_MapDosToLinear(0xa0000);
147 /* copy from virtual VGA frame buffer to DirectDraw surface */
148 for (Y
=0; Y
<Height
; Y
++,surf
+=Pitch
,dat
+=Width
) {
149 memcpy(surf
,dat
,Width
);
150 /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
154 EnterCriticalSection(&vga_crit
);
157 LeaveCriticalSection(&vga_crit
);
160 static BYTE palreg
,palcnt
;
161 static PALETTEENTRY paldat
;
163 void VGA_ioport_out( WORD port
, BYTE val
)
167 palreg
=val
; palcnt
=0; break;
169 ((BYTE
*)&paldat
)[palcnt
++]=val
<< 2;
171 VGA_SetPalette(&paldat
,palreg
++,1);
178 BYTE
VGA_ioport_in( WORD port
)
184 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
185 we need to fake the occurrence of the vertical refresh */
187 ret
=vga_refresh
?0x00:0x08;