-Fixed MESSAGE functions that were thunking down to 16 bits implementation.
[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 "windows.h"
10 #include "winbase.h"
11 #include "miscemu.h"
12 #include "vga.h"
13 #include "ddraw.h"
14 #include "debug.h"
15
16 static IDirectDraw *lpddraw = NULL;
17 static IDirectDrawSurface *lpddsurf;
18 static IDirectDrawPalette *lpddpal;
19 static DDSURFACEDESC sdesc;
20 static WORD poll_timer;
21 static CRITICAL_SECTION vga_crit;
22 static int vga_polling,vga_refresh;
23
24 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
25 {
26     if (lpddraw) VGA_Exit();
27     if (!lpddraw) {
28         DirectDrawCreate(NULL,&lpddraw,NULL);
29         if (!lpddraw) {
30             ERR(ddraw,"DirectDraw is not available\n");
31             return 1;
32         }
33         if (lpddraw->lpvtbl->fnSetDisplayMode(lpddraw,Xres,Yres,Depth)) {
34             ERR(ddraw,"DirectDraw does not support requested display mode\n");
35             lpddraw->lpvtbl->fnRelease(lpddraw);
36             lpddraw=NULL;
37             return 1;
38         }
39         lpddraw->lpvtbl->fnCreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
40         memset(&sdesc,0,sizeof(sdesc));
41         sdesc.dwSize=sizeof(sdesc);
42         sdesc.dwFlags = DDSD_CAPS;
43         sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
44         if (lpddraw->lpvtbl->fnCreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
45             ERR(ddraw,"DirectDraw surface is not available\n");
46             lpddraw->lpvtbl->fnRelease(lpddraw);
47             lpddraw=NULL;
48             return 1;
49         }
50         vga_refresh=0;
51         InitializeCriticalSection(&vga_crit);
52         MakeCriticalSectionGlobal(&vga_crit);
53         /* poll every 20ms (50fps should provide adequate responsiveness) */
54         poll_timer = CreateSystemTimer( 20, VGA_Poll );
55     }
56     return 0;
57 }
58
59 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
60 {
61     if (!lpddraw) return 1;
62     if (!lpddsurf) return 1;
63     if (Height) *Height=sdesc.dwHeight;
64     if (Width) *Width=sdesc.dwWidth;
65     if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
66     return 0;
67 }
68
69 void VGA_Exit(void)
70 {
71     if (lpddraw) {
72         SYSTEM_KillSystemTimer(poll_timer);
73         DeleteCriticalSection(&vga_crit);
74         lpddsurf->lpvtbl->fnRelease(lpddsurf);
75         lpddsurf=NULL;
76         lpddraw->lpvtbl->fnRelease(lpddraw);
77         lpddraw=NULL;
78     }
79 }
80
81 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
82 {
83     if (!lpddraw) return;
84     lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
85     lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
86 }
87
88 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
89 {
90     PALETTEENTRY pal[256];
91     int c;
92
93     if (!lpddraw) return;
94     for (c=0; c<len; c++) {
95         pal[c].peRed  =color[c].rgbRed;
96         pal[c].peGreen=color[c].rgbGreen;
97         pal[c].peBlue =color[c].rgbBlue;
98         pal[c].peFlags=0;
99     }
100     lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
101     lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
102 }
103
104 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
105 {
106     if (!lpddraw) return NULL;
107     if (!lpddsurf) return NULL;
108     if (lpddsurf->lpvtbl->fnLock(lpddsurf,NULL,&sdesc,0,0)) {
109         ERR(ddraw,"could not lock surface!\n");
110         return NULL;
111     }
112     if (Pitch) *Pitch=sdesc.lPitch;
113     if (Height) *Height=sdesc.dwHeight;
114     if (Width) *Width=sdesc.dwWidth;
115     if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
116     return sdesc.y.lpSurface;
117 }
118
119 void VGA_Unlock(void)
120 {
121     lpddsurf->lpvtbl->fnUnlock(lpddsurf,sdesc.y.lpSurface);
122 }
123
124 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
125  * stuff!
126  */
127 void VGA_Poll( WORD timer )
128 {
129     char *dat;
130     unsigned Pitch,Height,Width;
131     char *surf;
132     int Y;
133     /* int X; */
134
135     EnterCriticalSection(&vga_crit);
136     if (!vga_polling) {
137         vga_polling++;
138         LeaveCriticalSection(&vga_crit);
139         /* FIXME: optimize by doing this only if the data has actually changed
140          *        (in a way similar to DIBSection, perhaps) */
141         surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
142         if (!surf) return;
143         dat = DOSMEM_MapDosToLinear(0xa0000);
144         /* copy from virtual VGA frame buffer to DirectDraw surface */
145         for (Y=0; Y<Height; Y++,surf+=Pitch,dat+=Width) {
146             memcpy(surf,dat,Width);
147             /*for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);*/
148         }
149         VGA_Unlock();
150         vga_refresh=1;
151         EnterCriticalSection(&vga_crit);
152         vga_polling--;
153     }
154     LeaveCriticalSection(&vga_crit);
155 }
156
157 static BYTE palreg,palcnt;
158 static PALETTEENTRY paldat;
159
160 void VGA_ioport_out( WORD port, BYTE val )
161 {
162     switch (port) {
163         case 0x3c8:
164             palreg=val; palcnt=0; break;
165         case 0x3c9:
166             ((BYTE*)&paldat)[palcnt++]=val << 2;
167             if (palcnt==3) {
168                 VGA_SetPalette(&paldat,palreg,1);
169                 palreg++;
170             }
171             break;
172     }
173 }
174
175 BYTE VGA_ioport_in( WORD port )
176 {
177     BYTE ret;
178
179     switch (port) {
180         case 0x3da:
181             /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
182                we need to fake the occurrence of the vertical refresh */
183             if (lpddraw) {
184                 ret=vga_refresh?0x00:0x08;
185                 vga_refresh=0;
186             } else ret=0x08;
187             break;
188         default:
189             ret=0xff;
190     }
191     return ret;
192 }