Index: vid.c =================================================================== --- vid.c (revision 32098) +++ vid.c (working copy) @@ -36,8 +36,8 @@ { 0, 0, - 1200 - 1, - 900 - 1 + 640 - 1, + 480 - 1 }; ULONG TextColor = 0xF; @@ -50,7 +50,7 @@ VidInitialize( IN BOOLEAN SetMode) { -#if I_FINISHED_DEVELOPING +//#if I_FINISHED_DEVELOPING ULONG PciId; /* @@ -61,14 +61,22 @@ WRITE_PORT_ULONG((PULONG)0xcf8, 0x80000000); PciId = READ_PORT_ULONG((PULONG)0xcfc); if (0x02a510de == PciId) + { VidTable = &VidXboxTable; + } else if (SetMode) + { VidTable = &VidVgaTable; + } else + { VidTable = &VidVgaTextTable; -#else + } +/* + #else VidTable = &VidFramebufTable; #endif +*/ return VidTable->Initialize(SetMode); } Index: vid_xbox.c =================================================================== --- vid_xbox.c (revision 32098) +++ vid_xbox.c (working copy) @@ -24,23 +24,260 @@ #define NDEBUG #include -/* FUNCTIONS *****************************************************************/ +extern ULONG ScrollRegion[4]; +extern ULONG TextColor, curr_x, curr_y; +extern BOOLEAN NextLine; +extern UCHAR BitmapFont8x16[256 * 16]; +extern UCHAR BitmapFont10x18[256 * 18 * 2]; + +ULONG XboxVgaPalette[] = { + 0xFF000000, /* 0 black */ + 0xFF0000AD, /* 1 blue */ + 0xFF00AA00, /* 2 green */ + 0xFF00AAAD, /* 3 cyan */ + 0xFFAD0000, /* 4 red */ + 0xFFAD00AD, /* 5 magenta */ + 0xFFAD5500, /* 6 brown */ + 0xFFADAAAD, /* 7 light gray */ + 0xFF525552, /* 8 dark gray */ + 0xFF5255FF, /* 9 bright blue */ + 0xFF52FF52, /* 10 bright green */ + 0xFF52FFFF, /* 11 bright cyan */ + 0xFFFF5552, /* 12 bright red */ + 0xFFFF55FF, /* 13 bright magenta */ + 0xFFFFFF52, /* 14 bright yellow */ + 0xFFFFFFFF /* 15 bright white */ +}; + +ULONG XboxScreenPalette[16]; + +static BOOLEAN VidpInitialized = FALSE; +static PUCHAR VidpMemory = (VOID *)0xEE000000; +PUCHAR BackBuffer; + +#define CHAR_WIDTH 8 +#define CHAR_HEIGHT 16 +#define TOP_BOTTOM_LINES 0 + +#define DISPLAY_WIDTH 640 +#define DISPLAY_HEIGHT 480 + +UCHAR XboxBytesPerPixel = 4; + +/* PRIVATE FUNCTIONS **********************************************************/ + +VOID +NTAPI +XboxFbRedraw(VOID) +{ + ULONG X = 0; + ULONG Y = 0; + DWORD *PixelFB; + + PixelFB = (DWORD *)VidpMemory; + + while (Y < DISPLAY_HEIGHT) + { + while (X < DISPLAY_WIDTH) + { + PixelFB[(Y * DISPLAY_WIDTH) + X] = XboxScreenPalette[BackBuffer[(Y * DISPLAY_WIDTH) + X]]; + X++; + } + Y++; + X = 0; + } +} + +VOID +NTAPI +XboxDisplayCharacter(CHAR Character, + ULONG Left, + ULONG Top, + ULONG Color, + ULONG BackTextColor) +{ + PUCHAR FontPtr; + DWORD *PixelFB; /* FrameBuffer */ + UCHAR *PixelBB; /* BackBuffer */ + ULONG Mask; + ULONG Stride = DISPLAY_WIDTH * XboxBytesPerPixel; + unsigned Line; + unsigned Col; + UCHAR BytesPerChar = (CHAR_WIDTH <= 8) ? 1 : 2; + BOOLEAN Transparent = FALSE; + ULONG Color32 = 0; + ULONG BackTextColor32 = 0; + + /* Transform from VGA palette to XRGB8888 */ + if (Color < 16) + Color32 = XboxScreenPalette[Color]; + + if (BackTextColor < 16) + BackTextColor32 = XboxScreenPalette[BackTextColor]; + else + Transparent = TRUE; + + FontPtr = (PUCHAR)(BitmapFont8x16 + Character * CHAR_HEIGHT * BytesPerChar); + + PixelFB = (DWORD *) ((char *) VidpMemory + (Top + TOP_BOTTOM_LINES) * Stride + + Left * XboxBytesPerPixel); + PixelBB = (PUCHAR) ((char *) BackBuffer + (Top + TOP_BOTTOM_LINES) * DISPLAY_WIDTH + Left); + + for (Line = 0; Line < CHAR_HEIGHT; Line++) + { + Mask = (1 << (CHAR_WIDTH-1)); + for (Col = 0; Col < CHAR_WIDTH; Col++) + { + if (!Transparent) + { + PixelFB[Col] = (0 != (FontPtr[Line] & Mask) ? Color32 : BackTextColor32); + PixelBB[Col] = (UCHAR)(0 != (FontPtr[Line] & Mask) ? Color : BackTextColor); + } + else + { + PixelFB[Col] = (0 != (FontPtr[Line] & Mask) ? Color32 : XboxScreenPalette[PixelBB[Col]]); // transparent background + PixelBB[Col] = (UCHAR)(0 != (FontPtr[Line] & Mask) ? Color : PixelBB[Col]); // transparent background + } + + Mask = Mask >> 1; + } + PixelFB = (DWORD *) ((char *) PixelFB + Stride); + PixelBB = (PUCHAR) ((char *) PixelBB + DISPLAY_WIDTH); + } +} + +VOID +NTAPI +XboxScroll(ULONG Scroll) +{ + ULONG Top; + PUCHAR SourceOffset, DestOffset, j; + ULONG Offset; + ULONG i; + + /* Set memory positions of the scroll */ + SourceOffset = BackBuffer + + ((ScrollRegion[1] + 2) * DISPLAY_WIDTH) + + ScrollRegion[0]; + + DestOffset = SourceOffset + Scroll * DISPLAY_WIDTH; + + /* Save top and check if it's above the bottom */ + Top = ScrollRegion[1]; + if (Top > ScrollRegion[3]) return; + + /* Start loop */ + do + { + /* Set number of bytes to loop and start offset */ + Offset = ScrollRegion[0]; + j = SourceOffset; + + /* Check if this is part of the scroll region */ + if (Offset <= (ScrollRegion[2])) + { + /* Update position */ + i = DestOffset - SourceOffset; + + /* Loop the X axis */ + do + { + /* Write value in the new position so that we can do the scroll */ + RtlCopyMemory(j, j+i, 1); + + /* Move to the next memory location to write to */ + j += 1; + + /* Move to the next byte in the region */ + Offset++; + + /* Make sure we don't go past the scroll region */ + } while (Offset <= (ScrollRegion[2])); + } + + /* Move to the next line */ + SourceOffset += DISPLAY_WIDTH; + DestOffset += DISPLAY_WIDTH; + + /* Increase top */ + Top++; + + /* Make sure we don't go past the scroll region */ + } while (Top <= ScrollRegion[3]); + + /* OK, now draw the scrolled version to the framebuffer */ + XboxFbRedraw(); +} + +VOID +NTAPI +DisplayStringXY(PUCHAR String, + ULONG Left, + ULONG Top, + ULONG TextColor, + ULONG BackColor) +{ + /* Loop every character */ + while (*String) + { + /* Display a character */ + XboxDisplayCharacter(*String, Left, Top, TextColor, BackColor); + + /* Move to next character and next position */ + String++; + Left += CHAR_WIDTH; + } +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + static BOOLEAN NTAPI VidXboxInitialize( IN BOOLEAN SetMode) { + PHYSICAL_ADDRESS PhysicalAddress; + + if (!VidpInitialized) + { + /* Set the framebuffer adress hardcoded, no cookie for me :), + consider querying the nvidia chip for the whereabouts of it's framebuffer */ + PhysicalAddress.QuadPart = 0xF3C00000; + + /* Assume 4MB framebuffer */ + VidpMemory = MmMapIoSpace(PhysicalAddress, 0x400000, MmNonCached); + if (VidpMemory == NULL) + return FALSE; + + /* Now allocate the backbuffer that is used to accelerate scrolling, etc. */ + BackBuffer = ExAllocatePool(NonPagedPool, DISPLAY_WIDTH * DISPLAY_HEIGHT); + + /* Initialize the screen palette with the default vga palette */ + RtlCopyMemory(XboxScreenPalette, XboxVgaPalette, sizeof(XboxVgaPalette)); + + /* We have now initialized the driver */ + VidpInitialized = TRUE; + } + + DPRINT1("VidXboxInitialize(SetMode %d)\n", SetMode); return TRUE; } static VOID NTAPI VidXboxResetDisplay(VOID) { + VidXboxInitialize(TRUE); } static VOID NTAPI VidXboxCleanUp(VOID) { + if (VidpInitialized) + { + MmUnmapIoSpace(VidpMemory, 0x400000); + ExFreePool(BackBuffer); + VidpInitialized = FALSE; + } } static VOID NTAPI @@ -52,6 +289,44 @@ IN ULONG Height, IN ULONG Delta) { + ULONG x, y; + PUCHAR BufferPtr; + ULONG VidOffset; + UCHAR *PixelBB; /* The index based backbuffer */ + ULONG Color; + + PixelBB = (PUCHAR)BackBuffer; + + for (x = Left; x < Left + Width; x++) + { + BufferPtr = Buffer; + VidOffset = x + (Top * DISPLAY_WIDTH); + + if (((x - Left) % 2) == 0) + { + for (y = Top; y < Top + Height; y++) + { + Color = *BufferPtr >> 4; + + PixelBB[VidOffset] = (UCHAR)Color; + VidOffset += DISPLAY_WIDTH; + BufferPtr += Delta; + } + } + else + { + for (y = Top; y < Top + Height; y++) + { + Color = *BufferPtr & 0xf; + + PixelBB[VidOffset] = (UCHAR)Color; + VidOffset += DISPLAY_WIDTH; + BufferPtr += Delta; + } + + Buffer++; + } + } } static VOID NTAPI @@ -63,6 +338,35 @@ IN ULONG Height, IN LONG Delta) { + BOOLEAN ShiftLeft = TRUE; + UCHAR b; + ULONG x, y; + + /* Reset the destination. */ + RtlZeroMemory(Buffer, (Delta > 0 ? Delta : -Delta) * Height); + + for (y = Top; y < Top + Height; y++) + { + for (x = Left; x < Left + Width; x++) + { + /* Get the pixel data from our backbuffer */ + b = BackBuffer[x + y * DISPLAY_WIDTH]; + + /* Since we store 1 pixel per byte but the buffer wants 2 pixels per byte, + we shift every other byte four bits to the left */ + if (ShiftLeft) + { + b <<= 4; + ShiftLeft = FALSE; + } + else + { + ShiftLeft = TRUE; + } + + Buffer[(y - Top) * Delta + ((x - Left) >> 1)] |= b; + } + } } static VOID NTAPI @@ -71,6 +375,147 @@ IN ULONG Left, IN ULONG Top) { + PBITMAPINFOHEADER BitmapInfoHeader; + LPRGBQUAD Palette; + ULONG bfOffBits; + UCHAR ClrUsed; + ULONG Index; + LONG Delta; + + BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer; + Palette = (LPRGBQUAD)(Buffer + BitmapInfoHeader->biSize); + + if (BitmapInfoHeader->biClrUsed) + ClrUsed = BitmapInfoHeader->biClrUsed; + else + ClrUsed = 1 << BitmapInfoHeader->biBitCount; + + bfOffBits = BitmapInfoHeader->biSize + ClrUsed * sizeof(RGBQUAD); + + + for (Index = 0; Index < ClrUsed; Index++) + { + XboxScreenPalette[Index] = (0xFF << 24) | (Palette[Index].rgbRed << 16) | (Palette[Index].rgbGreen << 8) | (Palette[Index].rgbBlue); + } + + if (BitmapInfoHeader->biCompression == 2) + { + PUCHAR OutputBuffer; + ULONG InputPos, OutputPos; + ULONG x, y; + UCHAR b; + ULONG Length; + + Delta = (BitmapInfoHeader->biWidth + 1) >> 1; + OutputBuffer = ExAllocatePool(NonPagedPool, Delta * BitmapInfoHeader->biHeight); + RtlZeroMemory(OutputBuffer, Delta * BitmapInfoHeader->biHeight); + OutputPos = InputPos = 0; + Buffer += bfOffBits; + + while (InputPos < BitmapInfoHeader->biSizeImage && + OutputPos < (ULONG)Delta * BitmapInfoHeader->biHeight * 2) + { + Length = Buffer[InputPos++]; + if (Length > 0) + { + /* Encoded mode */ + b = Buffer[InputPos++]; + if (OutputPos % 2) + { + OutputBuffer[OutputPos >> 1] |= b & 0xf; + b = (b >> 4) | (b << 4); + Length--; + OutputPos++; + } + + memset(OutputBuffer + (OutputPos >> 1), b, Length / 2); + OutputPos += Length; + + if (Length & 1) + { + OutputBuffer[OutputPos >> 1] |= b & 0xf; + OutputPos++; + } + } + else + { + /* Absolute mode */ + b = Buffer[InputPos++]; + if (b == 0) + { + /* End of line */ + if (OutputPos % Delta) + OutputPos = ((OutputPos / Delta) + 1) * Delta; + } + else if (b == 1) + { + /* End of image */ + break; + } + else if (b == 2) + { + x = Buffer[InputPos++]; + y = Buffer[InputPos++]; + OutputPos = ((OutputPos / Delta) + y) * Delta + + ((OutputPos % Delta) + x); + } + else + { + Length = b; + if (Length) + { + if (OutputPos % 2) + { + ASSERT(FALSE); + } + + for (Index = 0; Index < (Length / 2); Index++) + { + b = Buffer[InputPos++]; + OutputBuffer[OutputPos >> 1] = b; + OutputPos += 2; + } + if (Length & 1) + { + b = Buffer[InputPos++]; + OutputBuffer[OutputPos >> 1] |= b >> 4; + OutputPos++; + } + } + + /* Word align */ + InputPos += (InputPos & 1); + } + } + } + + VidBufferToScreenBlt(OutputBuffer + + (Delta * (BitmapInfoHeader->biHeight - 1)), + Left, Top, BitmapInfoHeader->biWidth, + BitmapInfoHeader->biHeight, -Delta); + + ExFreePool(OutputBuffer); + } + else + { + Delta = ((BitmapInfoHeader->biWidth + 31) & ~31) >> 1; + if (BitmapInfoHeader->biHeight < 0) + { + VidBufferToScreenBlt(Buffer + bfOffBits, + Left, Top, BitmapInfoHeader->biWidth, + -BitmapInfoHeader->biHeight, Delta); + } + else + { + VidBufferToScreenBlt(Buffer + bfOffBits + + (Delta * (BitmapInfoHeader->biHeight - 1)), + Left, Top, BitmapInfoHeader->biWidth, + BitmapInfoHeader->biHeight, -Delta); + } + } + + /* OK, we have a new system palette, redraw the framebuffer with the new palette */ + XboxFbRedraw(); } static VOID NTAPI @@ -81,12 +526,102 @@ IN ULONG Bottom, IN ULONG Color) { + ULONG Line, Col; + PULONG p; + PUCHAR p2; + ULONG Color32; + + /* Sanity checks */ + if (Top > Bottom) + return; + if (Left > Right) + return; + Color32 = Color; + /* Translate color to the VGA palette */ + if (Color < 16) + Color32 = XboxScreenPalette[Color]; + + for (Line = Top; Line <= Bottom; Line++) + { + /* First do the frontbuffer */ + p = (PULONG)(VidpMemory + (Line * DISPLAY_WIDTH * XboxBytesPerPixel) + Left * XboxBytesPerPixel); + for (Col = 0; Col < (Right-Left); Col++) + { + *p++ = Color32; + } + /* Then the backbuffer */ + p2 = (PUCHAR)(BackBuffer + (Line * DISPLAY_WIDTH) + Left); + for (Col = 0; Col < (Right-Left); Col++) + { + *p2++ = (UCHAR)Color; + } + } } static VOID NTAPI VidXboxDisplayString( IN PCSTR String) { + ULONG TopDelta = CHAR_HEIGHT-2; + + /* Start looping the string */ + while (*String) + { + /* Treat new-line separately */ + if (*String == '\n') + { + /* Modify Y position */ + curr_y += TopDelta; + if (curr_y >= ScrollRegion[3]) + { + /* Scroll the view */ + XboxScroll(TopDelta); + curr_y -= TopDelta; + } + + /* Update current X */ + curr_x = ScrollRegion[0]; + } + else if (*String == '\r') + { + /* Update current X */ + curr_x = ScrollRegion[0]; + + /* Check if we're being followed by a new line */ + if (String[1] != '\n') NextLine = TRUE; + } + else + { + /* Check if we had a \n\r last time */ + if (NextLine) + { + NextLine = FALSE; + } + + /* Display this character */ + XboxDisplayCharacter(*String, curr_x, curr_y, TextColor, 16); + curr_x += CHAR_WIDTH; + + /* Check if we should scroll */ + if (curr_x > ScrollRegion[2]) + { + /* Update Y position and check if we should scroll it */ + curr_y += TopDelta; + if (curr_y > ScrollRegion[3]) + { + /* Do the scroll */ + XboxScroll(TopDelta); + curr_y -= TopDelta; + } + + /* Update X */ + curr_x = ScrollRegion[0]; + } + } + + /* Get the next character */ + String++; + } } static VOID NTAPI @@ -96,6 +631,12 @@ IN ULONG Left, IN BOOLEAN Transparent) { + ULONG BackColor; + + /* If the caller wanted transparent, then send the special value (16), else */ + /* use our default and call the helper routine. */ + BackColor = (Transparent) ? 16 : 14; + DisplayStringXY(String, Left, Top, 12, BackColor); } VID_FUNCTION_TABLE VidXboxTable = {