More code moved to the X11 driver (bitmap and palette and misc).
[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 "debug.h"
16
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;
24
25 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
26 {
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;
33         }
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;
39         }
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;
50         }
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 );
56     }
57     return 0;
58 }
59
60 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
61 {
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;
68 }
69
70 void VGA_Exit(void)
71 {
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;
79     }
80 }
81
82 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
83 {
84     if (!lpddraw) return;
85     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
86     IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
87 }
88
89 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
90 {
91     PALETTEENTRY pal[256];
92     int c;
93
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;
100     }
101     IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
102     IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
103 }
104
105 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
106 {
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;
112     }
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;
118 }
119
120 void VGA_Unlock(void)
121 {
122     IDirectDrawSurface_Unlock(lpddsurf,sdesc.y.lpSurface);
123 }
124
125 /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization
126  * stuff!
127  */
128 void VGA_Poll( WORD timer )
129 {
130     char *dat;
131     unsigned Pitch,Height,Width;
132     char *surf;
133     int Y;
134     /* int X; */
135
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);*/
149         }
150         VGA_Unlock();
151         vga_refresh=1;
152         EnterCriticalSection(&vga_crit);
153         vga_polling--;
154     }
155     LeaveCriticalSection(&vga_crit);
156 }
157
158 static BYTE palreg,palcnt;
159 static PALETTEENTRY paldat;
160
161 void VGA_ioport_out( WORD port, BYTE val )
162 {
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;
171             }
172             break;
173     }
174 }
175
176 BYTE VGA_ioport_in( WORD port )
177 {
178     BYTE ret;
179
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;
191     }
192     return ret;
193 }