Recovery of release 990110 after disk crash.
[wine.git] / graphics / vga.c
blob490074d936c029399e5df7f73068a4a3c4cd56dc
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 "windows.h"
10 #include "winbase.h"
11 #include "miscemu.h"
12 #include "vga.h"
13 #include "ddraw.h"
14 #include "debug.h"
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;
24 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
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;
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;
39 lpddraw->lpvtbl->fnCreatePalette(lpddraw,0,NULL,&lpddpal,NULL);
40 memset(&sdesc,0,sizeof(sdesc));
41 sdesc.dwSize=sizeof(sdesc);
42 if (lpddraw->lpvtbl->fnCreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
43 ERR(ddraw,"DirectDraw surface is not available\n");
44 lpddraw->lpvtbl->fnRelease(lpddraw);
45 lpddraw=NULL;
46 return 1;
48 vga_refresh=0;
49 InitializeCriticalSection(&vga_crit);
50 MakeCriticalSectionGlobal(&vga_crit);
51 /* poll every 20ms (50fps should provide adequate responsiveness) */
52 poll_timer = CreateSystemTimer( 20, VGA_Poll );
54 return 0;
57 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
59 if (!lpddraw) return 1;
60 if (!lpddsurf) return 1;
61 if (Height) *Height=sdesc.dwHeight;
62 if (Width) *Width=sdesc.dwWidth;
63 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
64 return 0;
67 void VGA_Exit(void)
69 if (lpddraw) {
70 SYSTEM_KillSystemTimer(poll_timer);
71 DeleteCriticalSection(&vga_crit);
72 lpddsurf->lpvtbl->fnRelease(lpddsurf);
73 lpddsurf=NULL;
74 lpddraw->lpvtbl->fnRelease(lpddraw);
75 lpddraw=NULL;
79 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
81 if (!lpddraw) return;
82 lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
83 lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
86 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
88 PALETTEENTRY pal[256];
89 int c;
91 if (!lpddraw) return;
92 for (c=0; c<len; c++) {
93 pal[c].peRed =color[c].rgbRed;
94 pal[c].peGreen=color[c].rgbGreen;
95 pal[c].peBlue =color[c].rgbBlue;
96 pal[c].peFlags=0;
98 lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal);
99 lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal);
102 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
104 if (!lpddraw) return NULL;
105 if (!lpddsurf) return NULL;
106 if (lpddsurf->lpvtbl->fnLock(lpddsurf,NULL,&sdesc,0,0)) {
107 ERR(ddraw,"could not lock surface!\n");
108 return NULL;
110 if (Pitch) *Pitch=sdesc.lPitch;
111 if (Height) *Height=sdesc.dwHeight;
112 if (Width) *Width=sdesc.dwWidth;
113 if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount;
114 return sdesc.y.lpSurface;
117 void VGA_Unlock(void)
119 lpddsurf->lpvtbl->fnUnlock(lpddsurf,sdesc.y.lpSurface);
122 void VGA_Poll( WORD timer )
124 char *dat;
125 unsigned Pitch,Height,Width;
126 char *surf;
127 int Y,X;
129 EnterCriticalSection(&vga_crit);
130 if (!vga_polling) {
131 vga_polling++;
132 LeaveCriticalSection(&vga_crit);
133 /* FIXME: optimize by doing this only if the data has actually changed
134 * (in a way similar to DIBSection, perhaps) */
135 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
136 if (!surf) return;
137 dat = DOSMEM_MapDosToLinear(0xa0000);
138 /* copy from virtual VGA frame buffer to DirectDraw surface */
139 for (Y=0; Y<Height; Y++,surf+=Pitch,dat+=Width) {
140 memcpy(surf,dat,Width);
141 for (X=0; X<Width; X++) if (dat[X]) TRACE(ddraw,"data(%d) at (%d,%d)\n",dat[X],X,Y);
143 VGA_Unlock();
144 vga_refresh=1;
145 EnterCriticalSection(&vga_crit);
146 vga_polling--;
148 LeaveCriticalSection(&vga_crit);
151 static BYTE palreg,palcnt;
152 static PALETTEENTRY paldat;
154 void VGA_ioport_out( WORD port, BYTE val )
156 switch (port) {
157 case 0x3c8:
158 palreg=val; palcnt=0; break;
159 case 0x3c9:
160 ((BYTE*)&paldat)[palcnt++]=val << 2;
161 if (palcnt==3) {
162 VGA_SetPalette(&paldat,palreg,1);
163 palreg++;
165 break;
169 BYTE VGA_ioport_in( WORD port )
171 BYTE ret;
173 switch (port) {
174 case 0x3da:
175 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
176 we need to fake the occurrence of the vertical refresh */
177 if (lpddraw) {
178 ret=vga_refresh?0x00:0x08;
179 vga_refresh=0;
180 } else ret=0x08;
181 break;
182 default:
183 ret=0xff;
185 return ret;