2 * VGA hardware emulation
4 * Copyright 1998 Ove Kåven (with some help from Marcus Meissner)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
34 static IDirectDraw *lpddraw = NULL;
35 static IDirectDrawSurface *lpddsurf;
36 static IDirectDrawPalette *lpddpal;
37 static DDSURFACEDESC sdesc;
38 static LONG vga_refresh;
39 static HANDLE poll_timer;
42 * VGA controller memory is emulated using linear framebuffer.
43 * This frambuffer also acts as an interface
44 * between VGA controller emulation and DirectDraw.
46 * vga_fb_width: Display width in pixels. Can be modified when
47 * display mode is changed.
48 * vga_fb_height: Display height in pixels. Can be modified when
49 * display mode is changed.
50 * vga_fb_depth: Number of bits used to store single pixel color information.
51 * Each pixel uses (vga_fb_depth+7)/8 bytes because
52 * 1-16 color modes are mapped to 256 color mode.
53 * Can be modified when display mode is changed.
54 * vga_fb_pitch: How many bytes to add to pointer in order to move
55 * from one row to another. This is fixed in VGA modes,
56 * but can be modified in SVGA modes.
57 * vga_fb_offset: Offset added to framebuffer start address in order
58 * to find the display origin. Programs use this to do
59 * double buffering and to scroll display. The value can
60 * be modified in VGA and SVGA modes.
61 * vga_fb_size: How many bytes are allocated to framebuffer.
62 * VGA framebuffers are always larger than display size and
63 * SVGA framebuffers may also be.
64 * vga_fb_data: Pointer to framebuffer start.
65 * vga_fb_window: Offset of 64k window 0xa0000 in bytes from framebuffer start.
66 * This value is >= 0, if mode uses linear framebuffer and
67 * -1, if mode uses color planes. This value is fixed
68 * in all modes except 0x13 (256 color VGA) where
69 * 0 means normal mode and -1 means Mode-X (unchained mode).
71 static int vga_fb_width;
72 static int vga_fb_height;
73 static int vga_fb_depth;
74 static int vga_fb_pitch;
75 static int vga_fb_offset;
76 static int vga_fb_size = 0;
77 static void *vga_fb_data = 0;
78 static int vga_fb_window = 0;
80 static BYTE vga_text_attr;
81 static char *textbuf_old = NULL;
84 * VGA controller ports 0x3c0, 0x3c4, 0x3ce and 0x3d4 are
85 * indexed registers. These ports are used to select VGA controller
86 * subregister that can be written to or read from using ports 0x3c1,
87 * 0x3c5, 0x3cf or 0x3d5. Selected subregister indexes are
88 * stored in variables vga_index_*.
90 * Port 0x3c0 is special because it is both index and
91 * data-write register. Flip-flop vga_address_3c0 tells whether
92 * the port acts currently as an address register. Reading from port
93 * 0x3da resets the flip-flop to address mode.
95 static BYTE vga_index_3c0;
96 static BYTE vga_index_3c4;
97 static BYTE vga_index_3ce;
98 static BYTE vga_index_3d4;
99 static BOOL vga_address_3c0 = TRUE;
101 static BOOL vga_mode_initialized = FALSE;
103 static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
105 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
106 static DirectDrawCreateProc pDirectDrawCreate;
108 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high );
110 static HWND vga_hwnd = (HWND) NULL;
113 * For simplicity, I'm creating a second palette.
114 * 16 color accesses will use these pointers and insert
115 * entries from the 64-color palette into the default
116 * palette. --Robert 'Admiral' Coeyman
119 static char vga_16_palette[17]={
120 0x00, /* 0 - Black */
122 0x02, /* 2 - Green */
125 0x05, /* 5 - Magenta */
126 0x14, /* 6 - Brown */
127 0x07, /* 7 - Light gray */
128 0x38, /* 8 - Dark gray */
129 0x39, /* 9 - Light blue */
130 0x3a, /* A - Light green */
131 0x3b, /* B - Light cyan */
132 0x3c, /* C - Light red */
133 0x3d, /* D - Light magenta */
134 0x3e, /* E - Yellow */
135 0x3f, /* F - White */
136 0x00 /* Border Color */
139 static PALETTEENTRY vga_def_palette[256]={
141 {0x00, 0x00, 0x00}, /* 0 - Black */
142 {0x00, 0x00, 0x80}, /* 1 - Blue */
143 {0x00, 0x80, 0x00}, /* 2 - Green */
144 {0x00, 0x80, 0x80}, /* 3 - Cyan */
145 {0x80, 0x00, 0x00}, /* 4 - Red */
146 {0x80, 0x00, 0x80}, /* 5 - Magenta */
147 {0x80, 0x80, 0x00}, /* 6 - Brown */
148 {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
149 {0x80, 0x80, 0x80}, /* 8 - Dark gray */
150 {0x00, 0x00, 0xFF}, /* 9 - Light blue */
151 {0x00, 0xFF, 0x00}, /* A - Light green */
152 {0x00, 0xFF, 0xFF}, /* B - Light cyan */
153 {0xFF, 0x00, 0x00}, /* C - Light red */
154 {0xFF, 0x00, 0xFF}, /* D - Light magenta */
155 {0xFF, 0xFF, 0x00}, /* E - Yellow */
156 {0xFF, 0xFF, 0xFF}, /* F - White */
157 {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
161 * This palette is the dos default, converted from 18 bit color to 24.
162 * It contains only 64 entries of colors--all others are zeros.
163 * --Robert 'Admiral' Coeyman
165 static PALETTEENTRY vga_def64_palette[256]={
167 {0x00, 0x00, 0x00}, /* 0x00 Black */
168 {0x00, 0x00, 0xaa}, /* 0x01 Blue */
169 {0x00, 0xaa, 0x00}, /* 0x02 Green */
170 {0x00, 0xaa, 0xaa}, /* 0x03 Cyan */
171 {0xaa, 0x00, 0x00}, /* 0x04 Red */
172 {0xaa, 0x00, 0xaa}, /* 0x05 Magenta */
173 {0xaa, 0xaa, 0x00}, /* 0x06 */
174 {0xaa, 0xaa, 0xaa}, /* 0x07 Light Gray */
175 {0x00, 0x00, 0x55}, /* 0x08 */
176 {0x00, 0x00, 0xff}, /* 0x09 */
177 {0x00, 0xaa, 0x55}, /* 0x0a */
178 {0x00, 0xaa, 0xff}, /* 0x0b */
179 {0xaa, 0x00, 0x55}, /* 0x0c */
180 {0xaa, 0x00, 0xff}, /* 0x0d */
181 {0xaa, 0xaa, 0x55}, /* 0x0e */
182 {0xaa, 0xaa, 0xff}, /* 0x0f */
183 {0x00, 0x55, 0x00}, /* 0x10 */
184 {0x00, 0x55, 0xaa}, /* 0x11 */
185 {0x00, 0xff, 0x00}, /* 0x12 */
186 {0x00, 0xff, 0xaa}, /* 0x13 */
187 {0xaa, 0x55, 0x00}, /* 0x14 Brown */
188 {0xaa, 0x55, 0xaa}, /* 0x15 */
189 {0xaa, 0xff, 0x00}, /* 0x16 */
190 {0xaa, 0xff, 0xaa}, /* 0x17 */
191 {0x00, 0x55, 0x55}, /* 0x18 */
192 {0x00, 0x55, 0xff}, /* 0x19 */
193 {0x00, 0xff, 0x55}, /* 0x1a */
194 {0x00, 0xff, 0xff}, /* 0x1b */
195 {0xaa, 0x55, 0x55}, /* 0x1c */
196 {0xaa, 0x55, 0xff}, /* 0x1d */
197 {0xaa, 0xff, 0x55}, /* 0x1e */
198 {0xaa, 0xff, 0xff}, /* 0x1f */
199 {0x55, 0x00, 0x00}, /* 0x20 */
200 {0x55, 0x00, 0xaa}, /* 0x21 */
201 {0x55, 0xaa, 0x00}, /* 0x22 */
202 {0x55, 0xaa, 0xaa}, /* 0x23 */
203 {0xff, 0x00, 0x00}, /* 0x24 */
204 {0xff, 0x00, 0xaa}, /* 0x25 */
205 {0xff, 0xaa, 0x00}, /* 0x26 */
206 {0xff, 0xaa, 0xaa}, /* 0x27 */
207 {0x55, 0x00, 0x55}, /* 0x28 */
208 {0x55, 0x00, 0xff}, /* 0x29 */
209 {0x55, 0xaa, 0x55}, /* 0x2a */
210 {0x55, 0xaa, 0xff}, /* 0x2b */
211 {0xff, 0x00, 0x55}, /* 0x2c */
212 {0xff, 0x00, 0xff}, /* 0x2d */
213 {0xff, 0xaa, 0x55}, /* 0x2e */
214 {0xff, 0xaa, 0xff}, /* 0x2f */
215 {0x55, 0x55, 0x00}, /* 0x30 */
216 {0x55, 0x55, 0xaa}, /* 0x31 */
217 {0x55, 0xff, 0x00}, /* 0x32 */
218 {0x55, 0xff, 0xaa}, /* 0x33 */
219 {0xff, 0x55, 0x00}, /* 0x34 */
220 {0xff, 0x55, 0xaa}, /* 0x35 */
221 {0xff, 0xff, 0x00}, /* 0x36 */
222 {0xff, 0xff, 0xaa}, /* 0x37 */
223 {0x55, 0x55, 0x55}, /* 0x38 Dark Gray */
224 {0x55, 0x55, 0xff}, /* 0x39 Light Blue */
225 {0x55, 0xff, 0x55}, /* 0x3a Light Green */
226 {0x55, 0xff, 0xff}, /* 0x3b Light Cyan */
227 {0xff, 0x55, 0x55}, /* 0x3c Light Red */
228 {0xff, 0x55, 0xff}, /* 0x3d Light Magenta */
229 {0xff, 0xff, 0x55}, /* 0x3e Yellow */
230 {0xff, 0xff, 0xff}, /* 0x3f White */
231 {0,0,0} /* The next 192 entries are all zeros */
234 static HANDLE VGA_timer;
235 static HANDLE VGA_timer_thread;
237 /* set the timer rate; called in the polling thread context */
238 static void CALLBACK set_timer_rate( ULONG_PTR arg )
242 when.s.LowPart = when.s.HighPart = 0;
243 SetWaitableTimer( VGA_timer, &when, arg, VGA_Poll, 0, FALSE );
246 static DWORD CALLBACK VGA_TimerThread( void *dummy )
248 for (;;) WaitForMultipleObjectsEx( 0, NULL, FALSE, INFINITE, TRUE );
251 static void VGA_DeinstallTimer(void)
253 if (VGA_timer_thread)
255 CancelWaitableTimer( VGA_timer );
256 CloseHandle( VGA_timer );
257 TerminateThread( VGA_timer_thread, 0 );
258 CloseHandle( VGA_timer_thread );
259 VGA_timer_thread = 0;
263 static void VGA_InstallTimer(unsigned Rate)
265 if (!VGA_timer_thread)
267 VGA_timer = CreateWaitableTimerA( NULL, FALSE, NULL );
268 VGA_timer_thread = CreateThread( NULL, 0, VGA_TimerThread, NULL, 0, NULL );
270 QueueUserAPC( set_timer_rate, VGA_timer_thread, (ULONG_PTR)Rate );
273 HANDLE VGA_AlphaConsole(void)
275 /* this assumes that no Win32 redirection has taken place, but then again,
276 * only 16-bit apps are likely to use this part of Wine... */
277 return GetStdHandle(STD_OUTPUT_HANDLE);
280 char*VGA_AlphaBuffer(void)
282 return (char *)0xb8000;
285 /*** GRAPHICS MODE ***/
288 unsigned Xres, Yres, Depth;
292 static void WINAPI VGA_DoExit(ULONG_PTR arg)
294 VGA_DeinstallTimer();
295 IDirectDrawSurface_SetPalette(lpddsurf,NULL);
296 IDirectDrawSurface_Release(lpddsurf);
298 IDirectDrawPalette_Release(lpddpal);
300 IDirectDraw_Release(lpddraw);
304 static void WINAPI VGA_DoSetMode(ULONG_PTR arg)
307 ModeSet *par = (ModeSet *)arg;
310 if (lpddraw) VGA_DoExit(0);
312 if (!pDirectDrawCreate)
314 HMODULE hmod = LoadLibraryA( "ddraw.dll" );
315 if (hmod) pDirectDrawCreate = (DirectDrawCreateProc)GetProcAddress( hmod, "DirectDrawCreate" );
316 if (!pDirectDrawCreate) {
317 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
321 res = pDirectDrawCreate(NULL,&lpddraw,NULL);
323 ERR("DirectDraw is not available (res = %lx)\n",res);
327 vga_hwnd = CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP|WS_VISIBLE,0,0,par->Xres,par->Yres,0,0,0,NULL);
329 ERR("Failed to create user window.\n");
330 IDirectDraw_Release(lpddraw);
336 SetWindowPos(vga_hwnd,0,0,0,par->Xres,par->Yres,SWP_NOMOVE|SWP_NOZORDER);
338 if ((res=IDirectDraw_SetCooperativeLevel(lpddraw,vga_hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE))) {
339 ERR("Could not set cooperative level to exclusive (%lx)\n",res);
342 if ((res=IDirectDraw_SetDisplayMode(lpddraw,par->Xres,par->Yres,par->Depth))) {
343 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par->Xres,par->Yres,par->Depth,res);
344 IDirectDraw_Release(lpddraw);
349 res=IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
351 ERR("Could not create palette (res = %lx)\n",res);
352 IDirectDraw_Release(lpddraw);
356 if ((res=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,vga_def_palette))) {
357 ERR("Could not set default palette entries (res = %lx)\n", res);
360 memset(&sdesc,0,sizeof(sdesc));
361 sdesc.dwSize=sizeof(sdesc);
362 sdesc.dwFlags = DDSD_CAPS;
363 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
364 if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
365 ERR("DirectDraw surface is not available\n");
366 IDirectDraw_Release(lpddraw);
370 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
372 /* poll every 20ms (50fps should provide adequate responsiveness) */
373 VGA_InstallTimer(20);
379 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
385 vga_fb_height = Yres;
386 vga_fb_depth = Depth;
388 vga_fb_pitch = Xres * ((Depth + 7) / 8);
390 newSize = Xres * Yres * ((Depth + 7) / 8);
391 if(newSize < 256 * 1024)
392 newSize = 256 * 1024;
394 if(vga_fb_size < newSize) {
396 HeapFree(GetProcessHeap(), 0, vga_fb_data);
397 vga_fb_data = HeapAlloc(GetProcessHeap(), 0, newSize);
398 vga_fb_size = newSize;
401 if(Xres >= 640 || Yres >= 480) {
409 VGA_SetWindowStart((Depth < 8) ? -1 : 0);
411 par.Depth = (Depth < 8) ? 8 : Depth;
413 vga_mode_initialized = TRUE;
415 MZ_RunInThread(VGA_DoSetMode, (ULONG_PTR)&par);
419 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
421 if (!lpddraw) return 1;
422 if (!lpddsurf) return 1;
423 if (Height) *Height=sdesc.dwHeight;
424 if (Width) *Width=sdesc.dwWidth;
425 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
431 if (lpddraw) MZ_RunInThread(VGA_DoExit, 0);
434 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
436 if (!lpddraw) return;
437 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
440 /* set a single [char wide] color in 16 color mode. */
441 void VGA_SetColor16(int reg,int color)
445 if (!lpddraw) return;
446 pal= &vga_def64_palette[color];
447 IDirectDrawPalette_SetEntries(lpddpal,0,reg,1,pal);
448 vga_16_palette[reg]=(char)color;
451 /* Get a single [char wide] color in 16 color mode. */
452 char VGA_GetColor16(int reg)
455 if (!lpddraw) return 0;
456 return (char)vga_16_palette[reg];
459 /* set all 17 [char wide] colors at once in 16 color mode. */
460 void VGA_Set16Palette(char *Table)
465 if (!lpddraw) return; /* return if we're in text only mode */
466 bcopy((void *)&vga_16_palette,(void *)Table,17);
467 /* copy the entries into the table */
468 for (c=0; c<17; c++) { /* 17 entries */
469 pal= &vga_def64_palette[(int)vga_16_palette[c]]; /* get color */
470 IDirectDrawPalette_SetEntries(lpddpal,0,c,1,pal); /* set entry */
471 TRACE("Palette register %d set to %d\n",c,(int)vga_16_palette[c]);
472 } /* end of the counting loop */
475 /* Get all 17 [ char wide ] colors at once in 16 color mode. */
476 void VGA_Get16Palette(char *Table)
479 if (!lpddraw) return; /* return if we're in text only mode */
480 bcopy((void *)Table,(void *)&vga_16_palette,17);
481 /* copy the entries into the table */
484 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
486 PALETTEENTRY pal[256];
489 if (!lpddraw) return;
490 for (c=0; c<len; c++) {
491 pal[c].peRed =color[c].rgbRed;
492 pal[c].peGreen=color[c].rgbGreen;
493 pal[c].peBlue =color[c].rgbBlue;
496 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
499 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
501 if (!lpddraw) return NULL;
502 if (!lpddsurf) return NULL;
503 if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
504 ERR("could not lock surface!\n");
507 if (Pitch) *Pitch=sdesc.u1.lPitch;
508 if (Height) *Height=sdesc.dwHeight;
509 if (Width) *Width=sdesc.dwWidth;
510 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
511 return sdesc.lpSurface;
514 void VGA_Unlock(void)
516 IDirectDrawSurface_Unlock(lpddsurf,sdesc.lpSurface);
520 * Set start of 64k window at 0xa0000 in bytes.
521 * If value is -1, initialize color plane support.
522 * If value is >= 0, window contains direct copy of framebuffer.
524 void VGA_SetWindowStart(int start)
526 if(start == vga_fb_window)
529 if(vga_fb_window == -1)
530 FIXME("Remove VGA memory emulation.\n");
532 memmove(vga_fb_data + vga_fb_window, (char *)0xa0000, 64 * 1024);
534 vga_fb_window = start;
536 if(vga_fb_window == -1)
537 FIXME("Install VGA memory emulation.\n");
539 memmove( (char *)0xa0000, vga_fb_data + vga_fb_window, 64 * 1024);
543 * Get start of 64k window at 0xa0000 in bytes.
544 * Value is -1 in color plane modes.
546 int VGA_GetWindowStart()
548 return vga_fb_window;
553 /* prepare the text mode video memory copy that is used to only
554 * update the video memory line that did get updated. */
555 void VGA_PrepareVideoMemCopy(unsigned Xres, unsigned Yres)
560 textbuf_old = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textbuf_old, Xres * Yres * 2); /* char + attr */
562 p = VGA_AlphaBuffer();
565 /* make sure the video mem copy contains the exact opposite of our
566 * actual text mode memory area to make sure the screen
567 * does get updated fully initially */
568 for (i=0; i < Xres*Yres*2; i++)
569 *p2++ ^= *p++; /* XOR it */
572 int VGA_SetAlphaMode(unsigned Xres,unsigned Yres)
576 if (lpddraw) VGA_Exit();
578 /* FIXME: Where to initialize text attributes? */
579 VGA_SetTextAttribute(0xf);
581 VGA_PrepareVideoMemCopy(Xres, Yres);
583 /* poll every 30ms (33fps should provide adequate responsiveness) */
584 VGA_InstallTimer(30);
588 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz);
592 BOOL VGA_GetAlphaMode(unsigned*Xres,unsigned*Yres)
594 CONSOLE_SCREEN_BUFFER_INFO info;
595 if(!GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info))
599 if (Xres) *Xres=info.dwSize.X;
600 if (Yres) *Yres=info.dwSize.Y;
605 void VGA_SetCursorShape(unsigned char start_options, unsigned char end)
607 CONSOLE_CURSOR_INFO cci;
609 /* standard cursor settings:
610 * 0x0607 == CGA, 0x0b0c == monochrome, 0x0d0e == EGA/VGA */
612 /* calculate percentage from bottom - assuming VGA (bottom 0x0e) */
613 cci.dwSize = ((end & 0x1f) - (start_options & 0x1f))/0x0e * 100;
614 if (!cci.dwSize) cci.dwSize++; /* NULL cursor would make SCCI() fail ! */
615 cci.bVisible = ((start_options & 0x60) != 0x20); /* invisible ? */
617 SetConsoleCursorInfo(VGA_AlphaConsole(),&cci);
620 void VGA_SetCursorPos(unsigned X,unsigned Y)
624 if (!poll_timer) VGA_SetAlphaMode(80, 25);
627 SetConsoleCursorPosition(VGA_AlphaConsole(),pos);
630 void VGA_GetCursorPos(unsigned*X,unsigned*Y)
632 CONSOLE_SCREEN_BUFFER_INFO info;
633 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
634 if (X) *X=info.dwCursorPosition.X;
635 if (Y) *Y=info.dwCursorPosition.Y;
638 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
646 EnterCriticalSection(&vga_lock);
648 info.Char.AsciiChar = ch;
649 info.Attributes = (WORD)attr;
657 VGA_GetAlphaMode(&XR, &YR);
658 dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
660 dest.Left = X + count;
661 dest.Right = X + count;
667 info.Attributes = *dat;
670 WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
673 LeaveCriticalSection(&vga_lock);
676 static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
678 unsigned width, height;
681 VGA_GetAlphaMode(&width, &height);
682 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
684 dat[1] = vga_text_attr;
687 void VGA_PutChar(BYTE ascii)
689 unsigned width, height, x, y, nx, ny;
691 EnterCriticalSection(&vga_lock);
693 VGA_GetAlphaMode(&width, &height);
694 VGA_GetCursorPos(&x, &y);
698 VGA_PutCharAt(' ', x, y);
703 x += ((x + 8) & ~7) - x;
719 VGA_PutCharAt(ascii, x, y);
724 * FIXME: add line wrapping and scrolling
727 WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
730 * The following is just a sanity check.
732 VGA_GetCursorPos(&nx, &ny);
733 if(nx != x || ny != y)
734 WARN("VGA emulator and text console have become unsynchronized.\n");
736 LeaveCriticalSection(&vga_lock);
739 void VGA_SetTextAttribute(BYTE attr)
741 vga_text_attr = attr;
742 SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
745 BOOL VGA_ClearText(unsigned row1, unsigned col1,
746 unsigned row2, unsigned col2,
749 unsigned width, height, x, y;
751 char *dat = VGA_AlphaBuffer();
752 HANDLE con = VGA_AlphaConsole();
754 /* return if we fail to get the height and width of the window */
755 if(!VGA_GetAlphaMode(&width, &height))
761 TRACE("dat = %p, width = %d, height = %d\n", dat, width, height);
763 EnterCriticalSection(&vga_lock);
765 for(y=row1; y<=row2; y++) {
768 FillConsoleOutputCharacterA(con, ' ', col2-col1+1, off, NULL);
769 FillConsoleOutputAttribute(con, attr, col2-col1+1, off, NULL);
771 for(x=col1; x<=col2; x++) {
772 char *ptr = dat + ((width*y + x) * 2);
778 LeaveCriticalSection(&vga_lock);
783 void VGA_ScrollUpText(unsigned row1, unsigned col1,
784 unsigned row2, unsigned col2,
785 unsigned lines, BYTE attr)
787 FIXME("not implemented\n");
790 void VGA_ScrollDownText(unsigned row1, unsigned col1,
791 unsigned row2, unsigned col2,
792 unsigned lines, BYTE attr)
794 FIXME("not implemented\n");
797 void VGA_GetCharacterAtCursor(BYTE *ascii, BYTE *attr)
799 unsigned width, height, x, y;
802 VGA_GetAlphaMode(&width, &height);
803 VGA_GetCursorPos(&x, &y);
804 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
813 /* FIXME: optimize by doing this only if the data has actually changed
814 * (in a way similar to DIBSection, perhaps) */
815 static void VGA_Poll_Graphics(void)
817 unsigned int Pitch, Height, Width, X, Y;
819 char *dat = vga_fb_data + vga_fb_offset;
820 int bpp = (vga_fb_depth + 7) / 8;
822 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
826 * Synchronize framebuffer contents.
828 if(vga_fb_window != -1)
829 memmove(vga_fb_data + vga_fb_window, (char *)0xa0000, 64 * 1024);
832 * Double VGA framebuffer (320x200 -> 640x400), if needed.
834 if(Height >= 2 * vga_fb_height && Width >= 2 * vga_fb_width && bpp == 1)
835 for (Y=0; Y<vga_fb_height; Y++,surf+=Pitch*2,dat+=vga_fb_pitch)
836 for (X=0; X<vga_fb_width; X++) {
840 surf[X*2+Pitch] = value;
841 surf[X*2+Pitch+1] = value;
844 for (Y=0; Y<vga_fb_height; Y++,surf+=Pitch,dat+=vga_fb_pitch)
845 memcpy(surf, dat, vga_fb_width * bpp);
850 static void VGA_Poll_Text(void)
852 char *dat, *old, *p_line;
853 unsigned int Height,Width,Y,X;
854 CHAR_INFO ch[256]; /* that should suffice for the largest text width */
857 HANDLE con = VGA_AlphaConsole();
858 BOOL linechanged = FALSE; /* video memory area differs from stored copy ? */
860 VGA_GetAlphaMode(&Width,&Height);
861 dat = VGA_AlphaBuffer();
862 old = textbuf_old; /* pointer to stored video mem copy */
863 siz.X = Width; siz.Y = 1;
864 off.X = 0; off.Y = 0;
865 /* copy from virtual VGA frame buffer to console */
866 for (Y=0; Y<Height; Y++) {
867 linechanged = memcmp(dat, old, Width*2);
870 /*TRACE("line %d changed\n", Y);*/
872 for (X=0; X<Width; X++) {
873 ch[X].Char.AsciiChar = *p_line++;
874 /* WriteConsoleOutputA doesn't like "dead" chars */
875 if (ch[X].Char.AsciiChar == '\0')
876 ch[X].Char.AsciiChar = ' ';
877 ch[X].Attributes = *p_line++;
879 dest.Top=Y; dest.Bottom=Y;
880 dest.Left=0; dest.Right=Width+1;
881 WriteConsoleOutputA(con, ch, siz, off, &dest);
882 memcpy(old, dat, Width*2);
884 /* advance to next text line */
890 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
892 if(!TryEnterCriticalSection(&vga_lock))
902 LeaveCriticalSection(&vga_lock);
905 static BYTE palreg,palcnt;
906 static PALETTEENTRY paldat;
908 void VGA_ioport_out( WORD port, BYTE val )
915 FIXME("Unsupported index, register 0x3c0: 0x%02x (value 0x%02x)\n",
917 vga_address_3c0 = !vga_address_3c0;
923 switch(vga_index_3c4) {
924 case 0x04: /* Sequencer: Memory Mode Register */
925 if(vga_fb_depth == 8)
926 VGA_SetWindowStart((val & 8) ? 0 : -1);
928 FIXME("Memory Mode Register not supported in this mode.\n");
931 FIXME("Unsupported index, register 0x3c4: 0x%02x (value 0x%02x)\n",
936 FIXME("Unsupported index, register 0x3c4: 0x%02x (value 0x%02x)\n",
940 palreg=val; palcnt=0; break;
942 ((BYTE*)&paldat)[palcnt++]=val << 2;
944 VGA_SetPalette(&paldat,palreg++,1);
952 FIXME("Unsupported index, register 0x3ce: 0x%02x (value 0x%02x)\n",
959 FIXME("Unsupported index, register 0x3d4: 0x%02x (value 0x%02x)\n",
963 FIXME("Unsupported VGA register: 0x%04x (value 0x%02x)\n", port, val);
967 BYTE VGA_ioport_in( WORD port )
973 FIXME("Unsupported index, register 0x3c0: 0x%02x\n",
977 switch(vga_index_3c4) {
978 case 0x04: /* Sequencer: Memory Mode Register */
979 return (VGA_GetWindowStart() == -1) ? 0xf7 : 0xff;
981 FIXME("Unsupported index, register 0x3c4: 0x%02x\n",
986 FIXME("Unsupported index, register 0x3ce: 0x%02x\n",
990 FIXME("Unsupported index, register 0x3d4: 0x%02x\n",
995 * Read from this register resets register 0x3c0 address flip-flop.
997 vga_address_3c0 = TRUE;
998 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
999 we need to fake the occurrence of the vertical refresh */
1000 ret=vga_refresh?0x00:0x0b; /* toggle video RAM and lightpen and VGA refresh bits ! */
1001 if (vga_mode_initialized)
1004 /* Also fake the occurence of the vertical refresh when no graphic
1005 mode has been set */
1006 vga_refresh=!vga_refresh;
1010 FIXME("Unsupported VGA register: 0x%04x\n", port);
1015 void VGA_Clean(void)
1018 VGA_DeinstallTimer();