Bugfix: free loaded library not before exit.
[wine/hacks.git] / graphics / vga.c
blobfef9469ec836c17375e4bf5fdd36a1b0be861810
1 /*
2 * VGA hardware emulation
3 *
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
6 */
8 #include <string.h>
9 #include "winbase.h"
10 #include "winuser.h"
11 #include "wine/winuser16.h"
12 #include "miscemu.h"
13 #include "vga.h"
14 #include "ddraw.h"
15 #include "debug.h"
17 static IDirectDraw *lpddraw = NULL;
18 static IDirectDrawSurface *lpddsurf;
19 static IDirectDrawPalette *lpddpal;
20 static DDSURFACEDESC sdesc;
21 static WORD poll_timer;
22 static CRITICAL_SECTION vga_crit;
23 static int vga_polling,vga_refresh;
25 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
27 if (lpddraw) VGA_Exit();
28 if (!lpddraw) {
29 DirectDrawCreate(NULL,&lpddraw,NULL);
30 if (!lpddraw) {
31 ERR(ddraw,"DirectDraw is not available\n");
32 return 1;
34 if (IDirectDraw_SetDisplayMode(lpddraw,Xres,Yres,Depth)) {
35 ERR(ddraw,"DirectDraw does not support requested display mode\n");
36 IDirectDraw_Release(lpddraw);
37 lpddraw=NULL;
38 return 1;
40 IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
41 memset(&sdesc,0,sizeof(sdesc));
42 sdesc.dwSize=sizeof(sdesc);
43 sdesc.dwFlags = DDSD_CAPS;
44 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
45 if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
46 ERR(ddraw,"DirectDraw surface is not available\n");
47 IDirectDraw_Release(lpddraw);
48 lpddraw=NULL;
49 return 1;
51 vga_refresh=0;
52 InitializeCriticalSection(&vga_crit);
53 MakeCriticalSectionGlobal(&vga_crit);
54 /* poll every 20ms (50fps should provide adequate responsiveness) */
55 poll_timer = CreateSystemTimer( 20, VGA_Poll );
57 return 0;
60 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
62 if (!lpddraw) return 1;
63 if (!lpddsurf) return 1;
64 if (Height) *Height=sdesc.dwHeight;
65 if (Width) *Width=sdesc.dwWidth;
66 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
67 return 0;
70 void VGA_Exit(void)
72 if (lpddraw) {
73 SYSTEM_KillSystemTimer(poll_timer);
74 DeleteCriticalSection(&vga_crit);
75 IDirectDrawSurface_Release(lpddsurf);
76 lpddsurf=NULL;
77 IDirectDraw_Release(lpddraw);
78 lpddraw=NULL;
82 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
84 if (!lpddraw) return;
85 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
86 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
89 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
91 PALETTEENTRY pal[256];
92 int c;
94 if (!lpddraw) return;
95 for (c=0; c<len; c++) {
96 pal[c].peRed =color[c].rgbRed;
97 pal[c].peGreen=color[c].rgbGreen;
98 pal[c].peBlue =color[c].rgbBlue;
99 pal[c].peFlags=0;
101 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
102 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
105 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
107 if (!lpddraw) return NULL;
108 if (!lpddsurf) return NULL;
109 if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
110 ERR(ddraw,"could not lock surface!\n");
111 return NULL;
113 if (Pitch) *Pitch=sdesc.lPitch;
114 if (Height) *Height=sdesc.dwHeight;
115 if (Width) *Width=sdesc.dwWidth;
116 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
117 return sdesc.y.lpSurface;
120 void VGA_Unlock(void)
122 IDirectDrawSurface_Unlock(lpddsurf,sdesc.y.lpSurface);
125 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
126 * stuff!
128 void VGA_Poll( WORD timer )
130 char *dat;
131 unsigned Pitch,Height,Width;
132 char *surf;
133 int Y;
134 /* int X; */
136 EnterCriticalSection(&vga_crit);
137 if (!vga_polling) {
138 vga_polling++;
139 LeaveCriticalSection(&vga_crit);
140 /* FIXME: optimize by doing this only if the data has actually changed
141 * (in a way similar to DIBSection, perhaps) */
142 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
143 if (!surf) return;
144 dat = DOSMEM_MapDosToLinear(0xa0000);
145 /* copy from virtual VGA frame buffer to DirectDraw surface */
146 for (Y=0; Y<Height; Y++,surf+=Pitch,dat+=Width) {
147 memcpy(surf,dat,Width);
148 /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
150 VGA_Unlock();
151 vga_refresh=1;
152 EnterCriticalSection(&vga_crit);
153 vga_polling--;
155 LeaveCriticalSection(&vga_crit);
158 static BYTE palreg,palcnt;
159 static PALETTEENTRY paldat;
161 void VGA_ioport_out( WORD port, BYTE val )
163 switch (port) {
164 case 0x3c8:
165 palreg=val; palcnt=0; break;
166 case 0x3c9:
167 ((BYTE*)&paldat)[palcnt++]=val << 2;
168 if (palcnt==3) {
169 VGA_SetPalette(&paldat,palreg++,1);
170 palcnt=0;
172 break;
176 BYTE VGA_ioport_in( WORD port )
178 BYTE ret;
180 switch (port) {
181 case 0x3da:
182 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
183 we need to fake the occurrence of the vertical refresh */
184 if (lpddraw) {
185 ret=vga_refresh?0x00:0x08;
186 vga_refresh=0;
187 } else ret=0x08;
188 break;
189 default:
190 ret=0xff;
192 return ret;