Reactos
at listview 391 lines 10 kB view raw
1/* 2 * PROJECT: ReactOS Boot Video Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Platform-independent common helpers and defines 5 * COPYRIGHT: Copyright 2010 Gregor Schneider <gregor.schneider@reactos.org> 6 * Copyright 2011 Rafal Harabien <rafalh@reactos.org> 7 * Copyright 2020 Stanislav Motylkov <x86corez@gmail.com> 8 */ 9 10#include "precomp.h" 11 12/* GLOBALS ********************************************************************/ 13 14/* 15 * Boot video driver default palette is similar to the standard 16-color 16 * CGA palette, but it has Red and Blue channels swapped, and also dark 17 * and light gray colors swapped. 18 */ 19const RGBQUAD VidpDefaultPalette[BV_MAX_COLORS] = 20{ 21 RGB( 0, 0, 0), /* Black */ 22 RGB(128, 0, 0), /* Red */ 23 RGB( 0, 128, 0), /* Green */ 24 RGB(128, 128, 0), /* Brown */ 25 RGB( 0, 0, 128), /* Blue */ 26 RGB(128, 0, 128), /* Magenta */ 27 RGB( 0, 128, 128), /* Cyan */ 28 RGB(128, 128, 128), /* Dark Gray */ 29 RGB(192, 192, 192), /* Light Gray */ 30 RGB(255, 0, 0), /* Light Red */ 31 RGB( 0, 255, 0), /* Light Green */ 32 RGB(255, 255, 0), /* Yellow */ 33 RGB( 0, 0, 255), /* Light Blue */ 34 RGB(255, 0, 255), /* Light Magenta */ 35 RGB( 0, 255, 255), /* Light Cyan */ 36 RGB(255, 255, 255), /* White */ 37}; 38 39/* PRIVATE FUNCTIONS **********************************************************/ 40 41static VOID 42BitBlt( 43 _In_ ULONG Left, 44 _In_ ULONG Top, 45 _In_ ULONG Width, 46 _In_ ULONG Height, 47 _In_reads_bytes_(Delta * Height) PUCHAR Buffer, 48 _In_ ULONG BitsPerPixel, 49 _In_ ULONG Delta) 50{ 51 ULONG X, Y, Pixel; 52 UCHAR Colors; 53 PUCHAR InputBuffer; 54 const ULONG Bottom = Top + Height; 55 const ULONG Right = Left + Width; 56 57 /* Check if the buffer isn't 4bpp */ 58 if (BitsPerPixel != 4) 59 { 60 /* FIXME: TODO */ 61 DbgPrint("Unhandled BitBlt\n" 62 "%lux%lu @ (%lu|%lu)\n" 63 "Bits Per Pixel %lu\n" 64 "Buffer: %p. Delta: %lu\n", 65 Width, 66 Height, 67 Left, 68 Top, 69 BitsPerPixel, 70 Buffer, 71 Delta); 72 return; 73 } 74 75 PrepareForSetPixel(); 76 77 /* 4bpp blitting */ 78 for (Y = Top; Y < Bottom; ++Y) 79 { 80 InputBuffer = Buffer; 81 82 for (X = Left, Pixel = 0; 83 X < Right; 84 ++X, ++Pixel) 85 { 86 if (Pixel % 2 == 0) 87 { 88 /* Extract colors at every two pixels */ 89 Colors = *InputBuffer++; 90 91 SetPixel(X, Y, Colors >> 4); 92 } 93 else 94 { 95 SetPixel(X, Y, Colors & 0x0F); 96 } 97 } 98 99 Buffer += Delta; 100 } 101} 102 103static VOID 104RleBitBlt( 105 _In_ ULONG Left, 106 _In_ ULONG Top, 107 _In_ ULONG Width, 108 _In_ ULONG Height, 109 _In_ PUCHAR Buffer) 110{ 111 ULONG YDelta; 112 ULONG x; 113 ULONG RleValue, NewRleValue; 114 ULONG Color, Color2; 115 ULONG i, j; 116 ULONG Code; 117 118 PrepareForSetPixel(); 119 120 /* Set Y height and current X value and start loop */ 121 YDelta = Top + Height - 1; 122 x = Left; 123 for (;;) 124 { 125 /* Get the current value and advance in the buffer */ 126 RleValue = *Buffer; 127 Buffer++; 128 if (RleValue) 129 { 130 /* Check if we've gone past the edge */ 131 if ((x + RleValue) > (Width + Left)) 132 { 133 /* Fixup the pixel value */ 134 RleValue = Left - x + Width; 135 } 136 137 /* Get the new value */ 138 NewRleValue = *Buffer; 139 140 /* Get the two colors */ 141 Color = NewRleValue >> 4; 142 Color2 = NewRleValue & 0xF; 143 144 /* Increase buffer position */ 145 Buffer++; 146 147 /* Check if we need to do a fill */ 148 if (Color == Color2) 149 { 150 /* Do a fill and continue the loop */ 151 RleValue += x; 152 VidSolidColorFill(x, YDelta, RleValue - 1, YDelta, (UCHAR)Color); 153 x = RleValue; 154 continue; 155 } 156 157 /* Check if the pixel value is 1 or below */ 158 if (RleValue > 1) 159 { 160 /* Set loop variables */ 161 for (i = (RleValue - 2) / 2 + 1; i > 0; --i) 162 { 163 /* Set the pixels */ 164 SetPixel(x, YDelta, (UCHAR)Color); 165 x++; 166 SetPixel(x, YDelta, (UCHAR)Color2); 167 x++; 168 169 /* Decrease pixel value */ 170 RleValue -= 2; 171 } 172 } 173 174 /* Check if there is any value at all */ 175 if (RleValue) 176 { 177 /* Set the pixel and increase position */ 178 SetPixel(x, YDelta, (UCHAR)Color); 179 x++; 180 } 181 182 /* Start over */ 183 continue; 184 } 185 186 /* Get the current pixel value */ 187 RleValue = *Buffer; 188 Code = RleValue; 189 switch (Code) 190 { 191 /* Case 0 */ 192 case 0: 193 { 194 /* Set new x value, decrease distance and restart */ 195 x = Left; 196 YDelta--; 197 Buffer++; 198 continue; 199 } 200 201 /* Case 1 */ 202 case 1: 203 { 204 /* Done */ 205 return; 206 } 207 208 /* Case 2 */ 209 case 2: 210 { 211 /* Set new x value, decrease distance and restart */ 212 Buffer++; 213 x += *Buffer; 214 Buffer++; 215 YDelta -= *Buffer; 216 Buffer++; 217 continue; 218 } 219 220 /* Other values */ 221 default: 222 { 223 Buffer++; 224 break; 225 } 226 } 227 228 /* Check if we've gone past the edge */ 229 if ((x + RleValue) > (Width + Left)) 230 { 231 /* Set fixed up loop count */ 232 i = RleValue - Left - Width + x; 233 234 /* Fixup pixel value */ 235 RleValue -= i; 236 } 237 else 238 { 239 /* Clear loop count */ 240 i = 0; 241 } 242 243 /* Check the value now */ 244 if (RleValue > 1) 245 { 246 /* Set loop variables */ 247 for (j = (RleValue - 2) / 2 + 1; j > 0; --j) 248 { 249 /* Get the new value */ 250 NewRleValue = *Buffer; 251 252 /* Get the two colors */ 253 Color = NewRleValue >> 4; 254 Color2 = NewRleValue & 0xF; 255 256 /* Increase buffer position */ 257 Buffer++; 258 259 /* Set the pixels */ 260 SetPixel(x, YDelta, (UCHAR)Color); 261 x++; 262 SetPixel(x, YDelta, (UCHAR)Color2); 263 x++; 264 265 /* Decrease pixel value */ 266 RleValue -= 2; 267 } 268 } 269 270 /* Check if there is any value at all */ 271 if (RleValue) 272 { 273 /* Set the pixel and increase position */ 274 Color = *Buffer >> 4; 275 Buffer++; 276 SetPixel(x, YDelta, (UCHAR)Color); 277 x++; 278 i--; 279 } 280 281 /* Check loop count now */ 282 if ((LONG)i > 0) 283 { 284 /* Decrease it */ 285 i--; 286 287 /* Set new position */ 288 Buffer = Buffer + (i / 2) + 1; 289 } 290 291 /* Check if we need to increase the buffer */ 292 if ((ULONG_PTR)Buffer & 1) Buffer++; 293 } 294} 295 296/* PUBLIC FUNCTIONS ***********************************************************/ 297 298VOID 299NTAPI 300VidBufferToScreenBlt( 301 _In_reads_bytes_(Delta * Height) PUCHAR Buffer, 302 _In_ ULONG Left, 303 _In_ ULONG Top, 304 _In_ ULONG Width, 305 _In_ ULONG Height, 306 _In_ ULONG Delta) 307{ 308 /* Make sure we have a width and height */ 309 if (!Width || !Height) 310 return; 311 312 /* Call the helper function */ 313 BitBlt(Left, Top, Width, Height, Buffer, 4, Delta); 314} 315 316VOID 317NTAPI 318VidBitBlt( 319 _In_ PUCHAR Buffer, 320 _In_ ULONG Left, 321 _In_ ULONG Top) 322{ 323 PBITMAPINFOHEADER BitmapInfoHeader; 324 LONG Delta; 325 PUCHAR BitmapOffset; 326 ULONG PaletteCount; 327 328 /* Get the Bitmap Header */ 329 BitmapInfoHeader = (PBITMAPINFOHEADER)Buffer; 330 331 /* Initialize the palette */ 332 PaletteCount = BitmapInfoHeader->biClrUsed ? 333 BitmapInfoHeader->biClrUsed : BV_MAX_COLORS; 334 InitPaletteWithTable((PULONG)(Buffer + BitmapInfoHeader->biSize), 335 PaletteCount); 336 337 /* Make sure we can support this bitmap */ 338 ASSERT((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biPlanes) <= 4); 339 340 /* 341 * Calculate the delta and align it on 32-bytes, then calculate 342 * the actual start of the bitmap data. 343 */ 344 Delta = (BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth) + 31; 345 Delta >>= 3; 346 Delta &= ~3; 347 BitmapOffset = Buffer + sizeof(BITMAPINFOHEADER) + PaletteCount * sizeof(ULONG); 348 349 /* Check the compression of the bitmap */ 350 if (BitmapInfoHeader->biCompression == BI_RLE4) 351 { 352 /* Make sure we have a width and a height */ 353 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight)) 354 { 355 /* We can use RLE Bit Blt */ 356 RleBitBlt(Left, 357 Top, 358 BitmapInfoHeader->biWidth, 359 BitmapInfoHeader->biHeight, 360 BitmapOffset); 361 } 362 } 363 else 364 { 365 /* Check if the height is negative */ 366 if (BitmapInfoHeader->biHeight < 0) 367 { 368 /* Make it positive in the header */ 369 BitmapInfoHeader->biHeight *= -1; 370 } 371 else 372 { 373 /* Update buffer offset */ 374 BitmapOffset += ((BitmapInfoHeader->biHeight - 1) * Delta); 375 Delta *= -1; 376 } 377 378 /* Make sure we have a width and a height */ 379 if ((BitmapInfoHeader->biWidth) && (BitmapInfoHeader->biHeight)) 380 { 381 /* Do the BitBlt */ 382 BitBlt(Left, 383 Top, 384 BitmapInfoHeader->biWidth, 385 BitmapInfoHeader->biHeight, 386 BitmapOffset, 387 BitmapInfoHeader->biBitCount, 388 Delta); 389 } 390 } 391}