Cosmetics.
[wine] / graphics / vga.c
1 /*
2  * VGA hardware emulation
3  * 
4  * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
5  *
6  */
7
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 "debugtools.h"
16
17 DEFAULT_DEBUG_CHANNEL(ddraw)
18
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;
26
27 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
28 {
29     if (lpddraw) VGA_Exit();
30     if (!lpddraw) {
31         DirectDrawCreate(NULL,&lpddraw,NULL);
32         if (!lpddraw) {
33             ERR("DirectDraw is not available\n");
34             return 1;
35         }
36         if (IDirectDraw_SetDisplayMode(lpddraw,Xres,Yres,Depth)) {
37             ERR("DirectDraw does not support requested display mode\n");
38             IDirectDraw_Release(lpddraw);
39             lpddraw=NULL;
40             return 1;
41         }
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("DirectDraw surface is not available\n");
49             IDirectDraw_Release(lpddraw);
50             lpddraw=NULL;
51             return 1;
52         }
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 );
58     }
59     return 0;
60 }
61
62 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
63 {
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.u.dwRGBBitCount;
69     return 0;
70 }
71
72 void VGA_Exit(void)
73 {
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;
81     }
82 }
83
84 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
85 {
86     if (!lpddraw) return;
87     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
88     IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
89 }
90
91 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
92 {
93     PALETTEENTRY pal[256];
94     int c;
95
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;
102     }
103     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
104     IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
105 }
106
107 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
108 {
109     if (!lpddraw) return NULL;
110     if (!lpddsurf) return NULL;
111     if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
112         ERR("could not lock surface!\n");
113         return NULL;
114     }
115     if (Pitch) *Pitch=sdesc.lPitch;
116     if (Height) *Height=sdesc.dwHeight;
117     if (Width) *Width=sdesc.dwWidth;
118     if (Depth) *Depth=sdesc.ddpfPixelFormat.u.dwRGBBitCount;
119     return sdesc.u1.lpSurface;
120 }
121
122 void VGA_Unlock(void)
123 {
124     IDirectDrawSurface_Unlock(lpddsurf,sdesc.u1.lpSurface);
125 }
126
127 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
128  * stuff!
129  */
130 void VGA_Poll( WORD timer )
131 {
132     char *dat;
133     unsigned Pitch,Height,Width;
134     char *surf;
135     int Y;
136     /* int X; */
137
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);*/
151         }
152         VGA_Unlock();
153         vga_refresh=1;
154         EnterCriticalSection(&vga_crit);
155         vga_polling--;
156     }
157     LeaveCriticalSection(&vga_crit);
158 }
159
160 static BYTE palreg,palcnt;
161 static PALETTEENTRY paldat;
162
163 void VGA_ioport_out( WORD port, BYTE val )
164 {
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;
173             }
174             break;
175     }
176 }
177
178 BYTE VGA_ioport_in( WORD port )
179 {
180     BYTE ret;
181
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;
193     }
194     return ret;
195 }