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.
66 static int vga_fb_width;
67 static int vga_fb_height;
68 static int vga_fb_depth;
69 static int vga_fb_pitch;
70 static int vga_fb_offset;
71 static int vga_fb_size = 0;
72 static void *vga_fb_data = 0;
74 static BYTE vga_text_attr;
75 static char *textbuf_old = NULL;
78 * VGA controller ports 0x3c0, 0x3c4, 0x3ce and 0x3d4 are
79 * indexed registers. These ports are used to select VGA controller
80 * subregister that can be written to or read from using ports 0x3c1,
81 * 0x3c5, 0x3cf or 0x3d5. Selected subregister indexes are
82 * stored in variables vga_index_*.
84 * Port 0x3c0 is special because it is both index and
85 * data-write register. Flip-flop vga_address_3c0 tells whether
86 * the port acts currently as an address register. Reading from port
87 * 0x3da resets the flip-flop to address mode.
89 static BYTE vga_index_3c0;
90 static BYTE vga_index_3c4;
91 static BYTE vga_index_3ce;
92 static BYTE vga_index_3d4;
93 static BOOL vga_address_3c0 = TRUE;
95 static BOOL vga_mode_initialized = FALSE;
97 static CRITICAL_SECTION vga_lock = CRITICAL_SECTION_INIT("VGA");
99 typedef HRESULT (WINAPI *DirectDrawCreateProc)(LPGUID,LPDIRECTDRAW *,LPUNKNOWN);
100 static DirectDrawCreateProc pDirectDrawCreate;
102 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high );
104 static HWND vga_hwnd = (HWND) NULL;
107 * For simplicity, I'm creating a second palette.
108 * 16 color accesses will use these pointers and insert
109 * entries from the 64-color palette into the default
110 * palette. --Robert 'Admiral' Coeyman
113 static char vga_16_palette[17]={
114 0x00, /* 0 - Black */
116 0x02, /* 2 - Green */
119 0x05, /* 5 - Magenta */
120 0x14, /* 6 - Brown */
121 0x07, /* 7 - Light gray */
122 0x38, /* 8 - Dark gray */
123 0x39, /* 9 - Light blue */
124 0x3a, /* A - Light green */
125 0x3b, /* B - Light cyan */
126 0x3c, /* C - Light red */
127 0x3d, /* D - Light magenta */
128 0x3e, /* E - Yellow */
129 0x3f, /* F - White */
130 0x00 /* Border Color */
133 static PALETTEENTRY vga_def_palette[256]={
135 {0x00, 0x00, 0x00}, /* 0 - Black */
136 {0x00, 0x00, 0x80}, /* 1 - Blue */
137 {0x00, 0x80, 0x00}, /* 2 - Green */
138 {0x00, 0x80, 0x80}, /* 3 - Cyan */
139 {0x80, 0x00, 0x00}, /* 4 - Red */
140 {0x80, 0x00, 0x80}, /* 5 - Magenta */
141 {0x80, 0x80, 0x00}, /* 6 - Brown */
142 {0xC0, 0xC0, 0xC0}, /* 7 - Light gray */
143 {0x80, 0x80, 0x80}, /* 8 - Dark gray */
144 {0x00, 0x00, 0xFF}, /* 9 - Light blue */
145 {0x00, 0xFF, 0x00}, /* A - Light green */
146 {0x00, 0xFF, 0xFF}, /* B - Light cyan */
147 {0xFF, 0x00, 0x00}, /* C - Light red */
148 {0xFF, 0x00, 0xFF}, /* D - Light magenta */
149 {0xFF, 0xFF, 0x00}, /* E - Yellow */
150 {0xFF, 0xFF, 0xFF}, /* F - White */
151 {0,0,0} /* FIXME: a series of continuous rainbow hues should follow */
155 * This palette is the dos default, converted from 18 bit color to 24.
156 * It contains only 64 entries of colors--all others are zeros.
157 * --Robert 'Admiral' Coeyman
159 static PALETTEENTRY vga_def64_palette[256]={
161 {0x00, 0x00, 0x00}, /* 0x00 Black */
162 {0x00, 0x00, 0xaa}, /* 0x01 Blue */
163 {0x00, 0xaa, 0x00}, /* 0x02 Green */
164 {0x00, 0xaa, 0xaa}, /* 0x03 Cyan */
165 {0xaa, 0x00, 0x00}, /* 0x04 Red */
166 {0xaa, 0x00, 0xaa}, /* 0x05 Magenta */
167 {0xaa, 0xaa, 0x00}, /* 0x06 */
168 {0xaa, 0xaa, 0xaa}, /* 0x07 Light Gray */
169 {0x00, 0x00, 0x55}, /* 0x08 */
170 {0x00, 0x00, 0xff}, /* 0x09 */
171 {0x00, 0xaa, 0x55}, /* 0x0a */
172 {0x00, 0xaa, 0xff}, /* 0x0b */
173 {0xaa, 0x00, 0x55}, /* 0x0c */
174 {0xaa, 0x00, 0xff}, /* 0x0d */
175 {0xaa, 0xaa, 0x55}, /* 0x0e */
176 {0xaa, 0xaa, 0xff}, /* 0x0f */
177 {0x00, 0x55, 0x00}, /* 0x10 */
178 {0x00, 0x55, 0xaa}, /* 0x11 */
179 {0x00, 0xff, 0x00}, /* 0x12 */
180 {0x00, 0xff, 0xaa}, /* 0x13 */
181 {0xaa, 0x55, 0x00}, /* 0x14 Brown */
182 {0xaa, 0x55, 0xaa}, /* 0x15 */
183 {0xaa, 0xff, 0x00}, /* 0x16 */
184 {0xaa, 0xff, 0xaa}, /* 0x17 */
185 {0x00, 0x55, 0x55}, /* 0x18 */
186 {0x00, 0x55, 0xff}, /* 0x19 */
187 {0x00, 0xff, 0x55}, /* 0x1a */
188 {0x00, 0xff, 0xff}, /* 0x1b */
189 {0xaa, 0x55, 0x55}, /* 0x1c */
190 {0xaa, 0x55, 0xff}, /* 0x1d */
191 {0xaa, 0xff, 0x55}, /* 0x1e */
192 {0xaa, 0xff, 0xff}, /* 0x1f */
193 {0x55, 0x00, 0x00}, /* 0x20 */
194 {0x55, 0x00, 0xaa}, /* 0x21 */
195 {0x55, 0xaa, 0x00}, /* 0x22 */
196 {0x55, 0xaa, 0xaa}, /* 0x23 */
197 {0xff, 0x00, 0x00}, /* 0x24 */
198 {0xff, 0x00, 0xaa}, /* 0x25 */
199 {0xff, 0xaa, 0x00}, /* 0x26 */
200 {0xff, 0xaa, 0xaa}, /* 0x27 */
201 {0x55, 0x00, 0x55}, /* 0x28 */
202 {0x55, 0x00, 0xff}, /* 0x29 */
203 {0x55, 0xaa, 0x55}, /* 0x2a */
204 {0x55, 0xaa, 0xff}, /* 0x2b */
205 {0xff, 0x00, 0x55}, /* 0x2c */
206 {0xff, 0x00, 0xff}, /* 0x2d */
207 {0xff, 0xaa, 0x55}, /* 0x2e */
208 {0xff, 0xaa, 0xff}, /* 0x2f */
209 {0x55, 0x55, 0x00}, /* 0x30 */
210 {0x55, 0x55, 0xaa}, /* 0x31 */
211 {0x55, 0xff, 0x00}, /* 0x32 */
212 {0x55, 0xff, 0xaa}, /* 0x33 */
213 {0xff, 0x55, 0x00}, /* 0x34 */
214 {0xff, 0x55, 0xaa}, /* 0x35 */
215 {0xff, 0xff, 0x00}, /* 0x36 */
216 {0xff, 0xff, 0xaa}, /* 0x37 */
217 {0x55, 0x55, 0x55}, /* 0x38 Dark Gray */
218 {0x55, 0x55, 0xff}, /* 0x39 Light Blue */
219 {0x55, 0xff, 0x55}, /* 0x3a Light Green */
220 {0x55, 0xff, 0xff}, /* 0x3b Light Cyan */
221 {0xff, 0x55, 0x55}, /* 0x3c Light Red */
222 {0xff, 0x55, 0xff}, /* 0x3d Light Magenta */
223 {0xff, 0xff, 0x55}, /* 0x3e Yellow */
224 {0xff, 0xff, 0xff}, /* 0x3f White */
225 {0,0,0} /* The next 192 entries are all zeros */
228 static HANDLE VGA_timer;
229 static HANDLE VGA_timer_thread;
231 /* set the timer rate; called in the polling thread context */
232 static void CALLBACK set_timer_rate( ULONG_PTR arg )
236 when.s.LowPart = when.s.HighPart = 0;
237 SetWaitableTimer( VGA_timer, &when, arg, VGA_Poll, 0, FALSE );
240 static DWORD CALLBACK VGA_TimerThread( void *dummy )
242 for (;;) WaitForMultipleObjectsEx( 0, NULL, FALSE, INFINITE, TRUE );
245 static void VGA_DeinstallTimer(void)
247 if (VGA_timer_thread)
249 CancelWaitableTimer( VGA_timer );
250 CloseHandle( VGA_timer );
251 TerminateThread( VGA_timer_thread, 0 );
252 CloseHandle( VGA_timer_thread );
253 VGA_timer_thread = 0;
257 static void VGA_InstallTimer(unsigned Rate)
259 if (!VGA_timer_thread)
261 VGA_timer = CreateWaitableTimerA( NULL, FALSE, NULL );
262 VGA_timer_thread = CreateThread( NULL, 0, VGA_TimerThread, NULL, 0, NULL );
264 QueueUserAPC( set_timer_rate, VGA_timer_thread, (ULONG_PTR)Rate );
267 HANDLE VGA_AlphaConsole(void)
269 /* this assumes that no Win32 redirection has taken place, but then again,
270 * only 16-bit apps are likely to use this part of Wine... */
271 return GetStdHandle(STD_OUTPUT_HANDLE);
274 char*VGA_AlphaBuffer(void)
276 return DOSMEM_MapDosToLinear(0xb8000);
279 /*** GRAPHICS MODE ***/
282 unsigned Xres, Yres, Depth;
286 static void WINAPI VGA_DoExit(ULONG_PTR arg)
288 VGA_DeinstallTimer();
289 IDirectDrawSurface_SetPalette(lpddsurf,NULL);
290 IDirectDrawSurface_Release(lpddsurf);
292 IDirectDrawPalette_Release(lpddpal);
294 IDirectDraw_Release(lpddraw);
298 static void WINAPI VGA_DoSetMode(ULONG_PTR arg)
301 ModeSet *par = (ModeSet *)arg;
304 if (lpddraw) VGA_DoExit(0);
306 if (!pDirectDrawCreate)
308 HMODULE hmod = LoadLibraryA( "ddraw.dll" );
309 if (hmod) pDirectDrawCreate = (DirectDrawCreateProc)GetProcAddress( hmod, "DirectDrawCreate" );
310 if (!pDirectDrawCreate) {
311 ERR("Can't lookup DirectDrawCreate from ddraw.dll.\n");
315 res = pDirectDrawCreate(NULL,&lpddraw,NULL);
317 ERR("DirectDraw is not available (res = %lx)\n",res);
321 vga_hwnd = CreateWindowExA(0,"STATIC","WINEDOS VGA",WS_POPUP|WS_VISIBLE,0,0,par->Xres,par->Yres,0,0,0,NULL);
323 ERR("Failed to create user window.\n");
324 IDirectDraw_Release(lpddraw);
330 SetWindowPos(vga_hwnd,0,0,0,par->Xres,par->Yres,SWP_NOMOVE|SWP_NOZORDER);
332 if ((res=IDirectDraw_SetCooperativeLevel(lpddraw,vga_hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE))) {
333 ERR("Could not set cooperative level to exclusive (%lx)\n",res);
336 if ((res=IDirectDraw_SetDisplayMode(lpddraw,par->Xres,par->Yres,par->Depth))) {
337 ERR("DirectDraw does not support requested display mode (%dx%dx%d), res = %lx!\n",par->Xres,par->Yres,par->Depth,res);
338 IDirectDraw_Release(lpddraw);
343 res=IDirectDraw_CreatePalette(lpddraw,DDPCAPS_8BIT,NULL,&lpddpal,NULL);
345 ERR("Could not create palette (res = %lx)\n",res);
346 IDirectDraw_Release(lpddraw);
350 if ((res=IDirectDrawPalette_SetEntries(lpddpal,0,0,256,vga_def_palette))) {
351 ERR("Could not set default palette entries (res = %lx)\n", res);
354 memset(&sdesc,0,sizeof(sdesc));
355 sdesc.dwSize=sizeof(sdesc);
356 sdesc.dwFlags = DDSD_CAPS;
357 sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
358 if (IDirectDraw_CreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) {
359 ERR("DirectDraw surface is not available\n");
360 IDirectDraw_Release(lpddraw);
364 IDirectDrawSurface_SetPalette(lpddsurf,lpddpal);
366 /* poll every 20ms (50fps should provide adequate responsiveness) */
367 VGA_InstallTimer(20);
373 int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth)
379 vga_fb_height = Yres;
380 vga_fb_depth = Depth;
382 vga_fb_pitch = Xres * ((Depth + 7) / 8);
384 newSize = Xres * Yres * ((Depth + 7) / 8);
385 if(newSize < 256 * 1024)
386 newSize = 256 * 1024;
388 if(vga_fb_size < newSize) {
390 HeapFree(GetProcessHeap(), 0, vga_fb_data);
391 vga_fb_data = HeapAlloc(GetProcessHeap(), 0, newSize);
392 vga_fb_size = newSize;
395 if(Xres >= 640 || Yres >= 480) {
403 par.Depth = (Depth < 8) ? 8 : Depth;
405 vga_mode_initialized = TRUE;
407 MZ_RunInThread(VGA_DoSetMode, (ULONG_PTR)&par);
411 int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth)
413 if (!lpddraw) return 1;
414 if (!lpddsurf) return 1;
415 if (Height) *Height=sdesc.dwHeight;
416 if (Width) *Width=sdesc.dwWidth;
417 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
423 if (lpddraw) MZ_RunInThread(VGA_DoExit, 0);
426 void VGA_SetPalette(PALETTEENTRY*pal,int start,int len)
428 if (!lpddraw) return;
429 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
432 /* set a single [char wide] color in 16 color mode. */
433 void VGA_SetColor16(int reg,int color)
437 if (!lpddraw) return;
438 pal= &vga_def64_palette[color];
439 IDirectDrawPalette_SetEntries(lpddpal,0,reg,1,pal);
440 vga_16_palette[reg]=(char)color;
443 /* Get a single [char wide] color in 16 color mode. */
444 char VGA_GetColor16(int reg)
447 if (!lpddraw) return 0;
448 return (char)vga_16_palette[reg];
451 /* set all 17 [char wide] colors at once in 16 color mode. */
452 void VGA_Set16Palette(char *Table)
457 if (!lpddraw) return; /* return if we're in text only mode */
458 bcopy((void *)&vga_16_palette,(void *)Table,17);
459 /* copy the entries into the table */
460 for (c=0; c<17; c++) { /* 17 entries */
461 pal= &vga_def64_palette[(int)vga_16_palette[c]]; /* get color */
462 IDirectDrawPalette_SetEntries(lpddpal,0,c,1,pal); /* set entry */
463 TRACE("Palette register %d set to %d\n",c,(int)vga_16_palette[c]);
464 } /* end of the counting loop */
467 /* Get all 17 [ char wide ] colors at once in 16 color mode. */
468 void VGA_Get16Palette(char *Table)
471 if (!lpddraw) return; /* return if we're in text only mode */
472 bcopy((void *)Table,(void *)&vga_16_palette,17);
473 /* copy the entries into the table */
476 void VGA_SetQuadPalette(RGBQUAD*color,int start,int len)
478 PALETTEENTRY pal[256];
481 if (!lpddraw) return;
482 for (c=0; c<len; c++) {
483 pal[c].peRed =color[c].rgbRed;
484 pal[c].peGreen=color[c].rgbGreen;
485 pal[c].peBlue =color[c].rgbBlue;
488 IDirectDrawPalette_SetEntries(lpddpal,0,start,len,pal);
491 LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth)
493 if (!lpddraw) return NULL;
494 if (!lpddsurf) return NULL;
495 if (IDirectDrawSurface_Lock(lpddsurf,NULL,&sdesc,0,0)) {
496 ERR("could not lock surface!\n");
499 if (Pitch) *Pitch=sdesc.u1.lPitch;
500 if (Height) *Height=sdesc.dwHeight;
501 if (Width) *Width=sdesc.dwWidth;
502 if (Depth) *Depth=sdesc.ddpfPixelFormat.u1.dwRGBBitCount;
503 return sdesc.lpSurface;
506 void VGA_Unlock(void)
508 IDirectDrawSurface_Unlock(lpddsurf,sdesc.lpSurface);
513 /* prepare the text mode video memory copy that is used to only
514 * update the video memory line that did get updated. */
515 void VGA_PrepareVideoMemCopy(unsigned Xres, unsigned Yres)
520 textbuf_old = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textbuf_old, Xres * Yres * 2); /* char + attr */
522 p = VGA_AlphaBuffer();
525 /* make sure the video mem copy contains the exact opposite of our
526 * actual text mode memory area to make sure the screen
527 * does get updated fully initially */
528 for (i=0; i < Xres*Yres*2; i++)
529 *p2++ ^= *p++; /* XOR it */
532 int VGA_SetAlphaMode(unsigned Xres,unsigned Yres)
536 if (lpddraw) VGA_Exit();
538 /* FIXME: Where to initialize text attributes? */
539 VGA_SetTextAttribute(0xf);
541 VGA_PrepareVideoMemCopy(Xres, Yres);
543 /* poll every 30ms (33fps should provide adequate responsiveness) */
544 VGA_InstallTimer(30);
548 SetConsoleScreenBufferSize(VGA_AlphaConsole(),siz);
552 BOOL VGA_GetAlphaMode(unsigned*Xres,unsigned*Yres)
554 CONSOLE_SCREEN_BUFFER_INFO info;
555 if(!GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info))
559 if (Xres) *Xres=info.dwSize.X;
560 if (Yres) *Yres=info.dwSize.Y;
565 void VGA_SetCursorShape(unsigned char start_options, unsigned char end)
567 CONSOLE_CURSOR_INFO cci;
569 /* standard cursor settings:
570 * 0x0607 == CGA, 0x0b0c == monochrome, 0x0d0e == EGA/VGA */
572 /* calculate percentage from bottom - assuming VGA (bottom 0x0e) */
573 cci.dwSize = ((end & 0x1f) - (start_options & 0x1f))/0x0e * 100;
574 if (!cci.dwSize) cci.dwSize++; /* NULL cursor would make SCCI() fail ! */
575 cci.bVisible = ((start_options & 0x60) != 0x20); /* invisible ? */
577 SetConsoleCursorInfo(VGA_AlphaConsole(),&cci);
580 void VGA_SetCursorPos(unsigned X,unsigned Y)
584 if (!poll_timer) VGA_SetAlphaMode(80, 25);
587 SetConsoleCursorPosition(VGA_AlphaConsole(),pos);
590 void VGA_GetCursorPos(unsigned*X,unsigned*Y)
592 CONSOLE_SCREEN_BUFFER_INFO info;
593 GetConsoleScreenBufferInfo(VGA_AlphaConsole(),&info);
594 if (X) *X=info.dwCursorPosition.X;
595 if (Y) *Y=info.dwCursorPosition.Y;
598 void VGA_WriteChars(unsigned X,unsigned Y,unsigned ch,int attr,int count)
606 EnterCriticalSection(&vga_lock);
608 info.Char.AsciiChar = ch;
609 info.Attributes = (WORD)attr;
617 VGA_GetAlphaMode(&XR, &YR);
618 dat = VGA_AlphaBuffer() + ((XR*Y + X) * 2);
620 dest.Left = X + count;
621 dest.Right = X + count;
627 info.Attributes = *dat;
630 WriteConsoleOutputA(VGA_AlphaConsole(), &info, siz, off, &dest);
633 LeaveCriticalSection(&vga_lock);
636 static void VGA_PutCharAt(BYTE ascii, unsigned x, unsigned y)
638 unsigned width, height;
641 VGA_GetAlphaMode(&width, &height);
642 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
644 dat[1] = vga_text_attr;
647 void VGA_PutChar(BYTE ascii)
649 unsigned width, height, x, y, nx, ny;
651 EnterCriticalSection(&vga_lock);
653 VGA_GetAlphaMode(&width, &height);
654 VGA_GetCursorPos(&x, &y);
658 VGA_PutCharAt(' ', x, y);
663 x += ((x + 8) & ~7) - x;
679 VGA_PutCharAt(ascii, x, y);
684 * FIXME: add line wrapping and scrolling
687 WriteFile(VGA_AlphaConsole(), &ascii, 1, NULL, NULL);
690 * The following is just a sanity check.
692 VGA_GetCursorPos(&nx, &ny);
693 if(nx != x || ny != y)
694 WARN("VGA emulator and text console have become unsynchronized.\n");
696 LeaveCriticalSection(&vga_lock);
699 void VGA_SetTextAttribute(BYTE attr)
701 vga_text_attr = attr;
702 SetConsoleTextAttribute(VGA_AlphaConsole(), attr);
705 BOOL VGA_ClearText(unsigned row1, unsigned col1,
706 unsigned row2, unsigned col2,
709 unsigned width, height, x, y;
711 char *dat = VGA_AlphaBuffer();
712 HANDLE con = VGA_AlphaConsole();
714 /* return if we fail to get the height and width of the window */
715 if(!VGA_GetAlphaMode(&width, &height))
721 TRACE("dat = %p, width = %d, height = %d\n", dat, width, height);
723 EnterCriticalSection(&vga_lock);
725 for(y=row1; y<=row2; y++) {
728 FillConsoleOutputCharacterA(con, ' ', col2-col1+1, off, NULL);
729 FillConsoleOutputAttribute(con, attr, col2-col1+1, off, NULL);
731 for(x=col1; x<=col2; x++) {
732 char *ptr = dat + ((width*y + x) * 2);
738 LeaveCriticalSection(&vga_lock);
743 void VGA_ScrollUpText(unsigned row1, unsigned col1,
744 unsigned row2, unsigned col2,
745 unsigned lines, BYTE attr)
747 FIXME("not implemented\n");
750 void VGA_ScrollDownText(unsigned row1, unsigned col1,
751 unsigned row2, unsigned col2,
752 unsigned lines, BYTE attr)
754 FIXME("not implemented\n");
757 void VGA_GetCharacterAtCursor(BYTE *ascii, BYTE *attr)
759 unsigned width, height, x, y;
762 VGA_GetAlphaMode(&width, &height);
763 VGA_GetCursorPos(&x, &y);
764 dat = VGA_AlphaBuffer() + ((width*y + x) * 2);
774 * Copy part of VGA framebuffer to VGA window.
776 static void VGA_CopyFrameToWindow(void)
778 /* FIXME: add implementation */
782 * Copy contents of VGA window to VGA framebuffer.
784 static void VGA_CopyWindowToFrame(void)
786 /* FIXME: fix implementation */
787 char *dat = DOSMEM_MapDosToLinear(0xa0000);
788 memmove(vga_fb_data, dat, 65536);
791 /* FIXME: optimize by doing this only if the data has actually changed
792 * (in a way similar to DIBSection, perhaps) */
793 static void VGA_Poll_Graphics(void)
795 unsigned int Pitch, Height, Width, X, Y;
797 char *dat = vga_fb_data + vga_fb_offset;
798 int bpp = (vga_fb_depth + 7) / 8;
800 surf = VGA_Lock(&Pitch,&Height,&Width,NULL);
804 * Synchronize framebuffer contents.
806 VGA_CopyWindowToFrame();
809 * Double VGA framebuffer (320x200 -> 640x400), if needed.
811 if(Height >= 2 * vga_fb_height && Width >= 2 * vga_fb_width && bpp == 1)
812 for (Y=0; Y<vga_fb_height; Y++,surf+=Pitch*2,dat+=vga_fb_pitch)
813 for (X=0; X<vga_fb_width; X++) {
817 surf[X*2+Pitch] = value;
818 surf[X*2+Pitch+1] = value;
821 for (Y=0; Y<vga_fb_height; Y++,surf+=Pitch,dat+=vga_fb_pitch)
822 memcpy(surf, dat, vga_fb_width * bpp);
827 static void VGA_Poll_Text(void)
829 char *dat, *old, *p_line;
830 unsigned int Height,Width,Y,X;
831 CHAR_INFO ch[256]; /* that should suffice for the largest text width */
834 HANDLE con = VGA_AlphaConsole();
835 BOOL linechanged = FALSE; /* video memory area differs from stored copy ? */
837 VGA_GetAlphaMode(&Width,&Height);
838 dat = VGA_AlphaBuffer();
839 old = textbuf_old; /* pointer to stored video mem copy */
840 siz.X = Width; siz.Y = 1;
841 off.X = 0; off.Y = 0;
842 /* copy from virtual VGA frame buffer to console */
843 for (Y=0; Y<Height; Y++) {
844 linechanged = memcmp(dat, old, Width*2);
847 /*TRACE("line %d changed\n", Y);*/
849 for (X=0; X<Width; X++) {
850 ch[X].Char.AsciiChar = *p_line++;
851 /* WriteConsoleOutputA doesn't like "dead" chars */
852 if (ch[X].Char.AsciiChar == '\0')
853 ch[X].Char.AsciiChar = ' ';
854 ch[X].Attributes = *p_line++;
856 dest.Top=Y; dest.Bottom=Y;
857 dest.Left=0; dest.Right=Width+1;
858 WriteConsoleOutputA(con, ch, siz, off, &dest);
859 memcpy(old, dat, Width*2);
861 /* advance to next text line */
867 static void CALLBACK VGA_Poll( LPVOID arg, DWORD low, DWORD high )
869 if(!TryEnterCriticalSection(&vga_lock))
879 LeaveCriticalSection(&vga_lock);
882 static BYTE palreg,palcnt;
883 static PALETTEENTRY paldat;
885 void VGA_ioport_out( WORD port, BYTE val )
892 FIXME("Unsupported index, register 0x3c0: 0x%02x (value 0x%02x)\n",
894 vga_address_3c0 = !vga_address_3c0;
900 FIXME("Unsupported index, register 0x3c4: 0x%02x (value 0x%02x)\n",
904 palreg=val; palcnt=0; break;
906 ((BYTE*)&paldat)[palcnt++]=val << 2;
908 VGA_SetPalette(&paldat,palreg++,1);
916 FIXME("Unsupported index, register 0x3ce: 0x%02x (value 0x%02x)\n",
923 FIXME("Unsupported index, register 0x3d4: 0x%02x (value 0x%02x)\n",
927 FIXME("Unsupported VGA register: 0x%04x (value 0x%02x)\n", port, val);
931 BYTE VGA_ioport_in( WORD port )
937 FIXME("Unsupported index, register 0x3c0: 0x%02x\n",
941 FIXME("Unsupported index, register 0x3c4: 0x%02x\n",
945 FIXME("Unsupported index, register 0x3ce: 0x%02x\n",
949 FIXME("Unsupported index, register 0x3d4: 0x%02x\n",
954 * Read from this register resets register 0x3c0 address flip-flop.
956 vga_address_3c0 = TRUE;
957 /* since we don't (yet?) serve DOS VM requests while VGA_Poll is running,
958 we need to fake the occurrence of the vertical refresh */
959 ret=vga_refresh?0x00:0x0b; /* toggle video RAM and lightpen and VGA refresh bits ! */
960 if (vga_mode_initialized)
963 /* Also fake the occurence of the vertical refresh when no graphic
965 vga_refresh=!vga_refresh;
969 FIXME("Unsupported VGA register: 0x%04x\n", port);
977 VGA_DeinstallTimer();