enhmetafile added
[wine/multimedia.git] / graphics / vga.c
blobbb212c392e4e5b7bd16640a746ebd7ab3475366f
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 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();
30 if (!lpddraw) {
31 DirectDrawCreate(NULL,&lpddraw,NULL);
32 if (!lpddraw) {
33 ERR(ddraw,"DirectDraw is not available\n");
34 return 1;
36 if (IDirectDraw_SetDisplayMode(lpddraw,Xres,Yres,Depth)) {
37 ERR(ddraw,"DirectDraw does not support requested display mode\n");
38 IDirectDraw_Release(lpddraw);
39 lpddraw=NULL;
40 return 1;
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);
50 lpddraw=NULL;
51 return 1;
53 vga_refresh=0;
54 InitializeCriticalSection(&vga_crit);
55 MakeCriticalSectionGlobal(&vga_crit);
56 /* poll every 20ms (50fps should provide adequate responsiveness) */
57 poll_timer = CreateSystemTimer( 20, VGA_Poll );
59 return 0;
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;
69 return 0;
72 void VGA_Exit(void)
74 if (lpddraw) {
75 SYSTEM_KillSystemTimer(poll_timer);
76 DeleteCriticalSection(&vga_crit);
77 IDirectDrawSurface_Release(lpddsurf);
78 lpddsurf=NULL;
79 IDirectDraw_Release(lpddraw);
80 lpddraw=NULL;
84 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
86 if (!lpddraw) return;
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];
94 int c;
96 if (!lpddraw) return;
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;
101 pal[c].peFlags=0;
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");
113 return NULL;
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
128 * stuff!
130 void VGA_Poll( WORD timer )
132 char *dat;
133 unsigned Pitch,Height,Width;
134 char *surf;
135 int Y;
136 /* int X; */
138 EnterCriticalSection(&vga_crit);
139 if (!vga_polling) {
140 vga_polling++;
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);
145 if (!surf) return;
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);*/
152 VGA_Unlock();
153 vga_refresh=1;
154 EnterCriticalSection(&vga_crit);
155 vga_polling--;
157 LeaveCriticalSection(&vga_crit);
160 static BYTE palreg,palcnt;
161 static PALETTEENTRY paldat;
163 void VGA_ioport_out( WORD port, BYTE val )
165 switch (port) {
166 case 0x3c8:
167 palreg=val; palcnt=0; break;
168 case 0x3c9:
169 ((BYTE*)&paldat)[palcnt++]=val << 2;
170 if (palcnt==3) {
171 VGA_SetPalette(&paldat,palreg++,1);
172 palcnt=0;
174 break;
178 BYTE VGA_ioport_in( WORD port )
180 BYTE ret;
182 switch (port) {
183 case 0x3da:
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 */
186 if (lpddraw) {
187 ret=vga_refresh?0x00:0x08;
188 vga_refresh=0;
189 } else ret=0x08;
190 break;
191 default:
192 ret=0xff;
194 return ret;