20#include "pedigree/kernel/BootstrapInfo.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Service.h"
24#include "pedigree/kernel/ServiceFeatures.h"
25#include "pedigree/kernel/ServiceManager.h"
26#include "pedigree/kernel/core/BootIO.h"
27#include "pedigree/kernel/graphics/Graphics.h"
28#include "pedigree/kernel/graphics/GraphicsService.h"
29#include "pedigree/kernel/machine/Display.h"
30#include "pedigree/kernel/machine/Framebuffer.h"
31#include "pedigree/kernel/machine/InputManager.h"
32#include "pedigree/kernel/process/Mutex.h"
33#include "pedigree/kernel/process/TerminationDeferral.h"
34#include "pedigree/kernel/processor/types.h"
35#include "pedigree/kernel/utilities/Cord.h"
36#include "pedigree/kernel/utilities/StaticString.h"
37#include "pedigree/kernel/utilities/String.h"
38#include "pedigree/kernel/utilities/Vector.h"
39#include "pedigree/kernel/utilities/assert.h"
40#include "pedigree/kernel/utilities/utility.h"
44#include "modules/Module.h"
48static uint8_t* g_pBuffer = 0;
50static size_t g_Width = 0;
51static size_t g_Height = 0;
52static size_t g_DesiredWidth = 1024;
53static size_t g_DesiredHeight = 768;
54static size_t g_DesiredBpp = 32;
56static uint32_t g_BackgroundColour = 0x000000;
57static uint32_t g_ForegroundColour = 0xFFFFFF;
58static uint32_t g_ProgressBorderColour = 0x965000;
59static uint32_t g_ProgressColour = 0x966400;
61static Graphics::PixelFormat g_ColorFormat = Graphics::Bits24_Rgb;
63static size_t g_ProgressX, g_ProgressY;
64static size_t g_ProgressW, g_ProgressH;
65static size_t g_LogBoxX, g_LogBoxY;
66static size_t g_LogX, g_LogY;
67static size_t g_LogW, g_LogH;
71static size_t g_Previous = 0;
72static bool g_LogMode =
true;
74static bool g_NoGraphics =
false;
76static Mutex g_PrintLock;
78static void printChar(
char c,
size_t x,
size_t y) {
82 g_pFramebuffer->
blit(g_pFont, 0, c * FONT_HEIGHT, x, y, FONT_WIDTH, FONT_HEIGHT);
85static bool printChar(
char c) {
86 if (!g_pFramebuffer) {
95 g_LogX = (g_LogX + 8) & ~7;
96 }
else if (c ==
'\r') {
98 }
else if (c ==
'\n') {
101 }
else if (c >=
' ') {
102 g_pFramebuffer->
blit(g_pFont, 0, c * FONT_HEIGHT, g_LogBoxX + (g_LogX * FONT_WIDTH),
103 g_LogBoxY + (g_LogY * FONT_HEIGHT), FONT_WIDTH, FONT_HEIGHT);
107 if (g_LogX >= g_LogW / FONT_WIDTH) {
113 if (g_LogY >= (g_LogH / FONT_HEIGHT)) {
115 size_t diff = g_LogY - (g_LogH / FONT_HEIGHT) + 1;
118 g_pFramebuffer->
copy(g_LogBoxX, g_LogBoxY + (diff * FONT_HEIGHT), g_LogBoxX, g_LogBoxY, g_LogW,
119 ((g_LogH / FONT_HEIGHT) - diff) * FONT_HEIGHT);
120 g_pFramebuffer->
rect(g_LogBoxX, g_LogBoxY + ((g_LogH / FONT_HEIGHT) - diff) * FONT_HEIGHT,
121 g_LogW, diff * FONT_HEIGHT, g_BackgroundColour, g_ColorFormat);
129static bool printString(
const char* str,
size_t len = 0) {
131 len = StringLength(str);
135 bool scrolled =
false;
136 for (
size_t i = 0; i < len; i++) {
137 if (printChar(str[i])) {
149 if (s.length() >= 79) {
157 else if (str[1] ==
'E' || str[1] ==
'F')
159 else if (str[1] ==
'D')
160 c = BootIO::DarkGrey;
162 bootIO.
write(s, c, BootIO::Black);
168static void printString(
const LogCord& str) {
177 size_t firstRow = g_LogY;
178 bool scrolled =
false;
179 if (!g_NoGraphics && g_pFramebuffer) {
182 parent = g_pFramebuffer->getParent();
183 g_pFramebuffer->setParent(
nullptr);
185 for (
auto it = str.segbegin(); it != str.segend(); ++it) {
186 if (printString(it.ptr(), it.length())) {
191 g_pFramebuffer->setParent(parent);
195 g_pFramebuffer->
redraw(g_LogBoxX, g_LogBoxY + firstRow * FONT_HEIGHT, g_LogW,
196 (g_LogY - firstRow + 1) * FONT_HEIGHT,
false);
201static void printStringAt(
const char* str,
size_t x,
size_t y) {
203 for (
size_t i = 0; i < StringLength(str); i++) {
204 printChar(str[i], x, y);
209static void centerStringAt(
const char* str,
size_t midX,
size_t midY) {
211 size_t stringWidth = StringLength(str) * FONT_WIDTH;
212 size_t stringHeight = FONT_HEIGHT;
214 size_t x = midX - (stringWidth / 2);
215 size_t y = midY - (stringHeight / 2);
216 printStringAt(str, x, y);
232StreamingScreenLogger::~StreamingScreenLogger() =
default;
240 uint64_t key = note.data.key.key;
249 g_LogY += (g_LogBoxY / FONT_HEIGHT);
250 g_LogX = (g_LogBoxX / FONT_WIDTH);
251 g_LogBoxX = g_LogBoxY = 0;
258static void progress(
const char* text) {
259 const bool bFinished =
260 g_BootProgressTotal && ((g_BootProgressCurrent + 1) >= g_BootProgressTotal);
276 if (g_BootProgressTotal == 0)
283 for (
size_t i = 0; i < (80 / 2) - 11; ++i) {
284 bootIO.
write(s, BootIO::Black, BootIO::Black);
289 size_t pos = (20 * g_BootProgressCurrent) / g_BootProgressTotal;
290 for (
size_t i = 0; i < 20; ++i) {
297 bootIO.
write(s, BootIO::White, BootIO::Black);
298 }
else if (g_LogMode && g_LogH == g_Height) {
300 NOTICE(
"splash: destroying font pixel buffer");
302 NOTICE(
"splash: destroying font heap buffer");
305 NOTICE(
"splash: destroying framebuffer");
306 Graphics::destroyFramebuffer(g_pFramebuffer);
307 NOTICE(
"splash: destroyed framebuffer");
310 g_BootProgressUpdate = 0;
312 }
else if (g_pFramebuffer) {
313 size_t w = (g_ProgressW * g_BootProgressCurrent) / g_BootProgressTotal;
314 if (g_Previous <= g_BootProgressCurrent)
315 g_pFramebuffer->
rect(g_ProgressX, g_ProgressY, w, g_ProgressH, g_ProgressColour,
318 g_pFramebuffer->
rect(g_ProgressX + w, g_ProgressY, g_ProgressW - w, g_ProgressH,
319 g_BackgroundColour, g_ColorFormat);
320 g_Previous = g_BootProgressCurrent;
323 StringFormat(buf,
"%d%%", ((g_BootProgressCurrent * 100) / g_BootProgressTotal));
324 centerStringAt(buf, g_ProgressX + (g_ProgressW / 2), g_ProgressY - FONT_HEIGHT);
326 g_pFramebuffer->
redraw(g_ProgressX, g_ProgressY - (FONT_HEIGHT * 2), g_ProgressW,
327 g_ProgressH + (FONT_HEIGHT * 2),
true);
331 NOTICE(
"splash: destroying font pixel buffer");
333 NOTICE(
"splash: destroying font heap buffer");
337 NOTICE(
"splash: destroying framebuffer");
338 Graphics::destroyFramebuffer(g_pFramebuffer);
339 NOTICE(
"splash: destroyed framebuffer");
343 g_BootProgressUpdate = 0;
348static bool parseVideoMode(
const char* value) {
350 for (
size_t i = 0; i < 3; ++i) {
351 if (*value <
'0' || *value >
'9') {
354 while (*value >=
'0' && *value <=
'9') {
355 mode[i] = mode[i] * 10 + (*value++ -
'0');
356 if (mode[i] > 65535) {
360 if (!mode[i] || *value != (i == 2 ?
'\0' :
'x')) {
371 g_DesiredWidth = mode[0];
372 g_DesiredHeight = mode[1];
373 g_DesiredBpp = mode[2];
377static bool parseColour(
const char* value, uint32_t& colour) {
378 if (StringLength(value) != 6) {
383 for (
size_t i = 0; i < 6; ++i) {
386 if (c >=
'0' && c <=
'9') {
388 }
else if (c >=
'a' && c <=
'f') {
389 digit = c -
'a' + 10;
390 }
else if (c >=
'A' && c <=
'F') {
391 digit = c -
'A' + 10;
395 result = (result << 4) | digit;
401static bool handleNoSplash() {
404 const String title(
"Pedigree is Loading...\n");
410 for (
size_t i = 0; i < 2; ++i) {
411 bootIO.
write(s, BootIO::Black, BootIO::Black);
416 for (
size_t i = 0; i < (80 / 2) - (title.length() / 2); ++i) {
417 bootIO.
write(s, BootIO::Black, BootIO::Black);
422 bootIO.
write(s, BootIO::White, BootIO::Black);
424 g_BootProgressUpdate = &progress;
429static bool handleSplash() {
430 g_NoGraphics =
false;
433 g_GraphicsParams.wantTextMode =
false;
440 bool bSuccess =
false;
444 sizeof(g_GraphicsParams));
446 if (!(bSuccess && g_GraphicsParams.providerFound)) {
448 "splash: this system does not support graphics, using fallback "
450 return handleNoSplash();
453 Display* pDisplay = g_GraphicsParams.providerResult.pDisplay;
455 size_t nDesiredWidth = g_DesiredWidth;
456 size_t nDesiredHeight = g_DesiredHeight;
457 size_t nDesiredBpp = g_DesiredBpp;
460 if (!(nDesiredWidth && nDesiredHeight && nDesiredBpp) ||
461 !pDisplay->
setScreenMode(nDesiredWidth, nDesiredHeight, nDesiredBpp)) {
467 nDesiredWidth = currentMode.width;
468 nDesiredHeight = currentMode.height;
469 nDesiredBpp = currentMode.pf.
nBpp;
471 bool bModeFound =
true;
474 NOTICE(
"splash: Falling back to 1024x768x24");
477 NOTICE(
"splash: Falling back to 800x600x24");
480 NOTICE(
"splash: Falling back to 640x480x24");
489 NOTICE(
"splash: Falling back to 1024x768x16");
492 NOTICE(
"splash: Falling back to 800x600x16");
495 NOTICE(
"splash: Falling back to 640x480x16");
498 "splash: Couldn't find a suitable display mode "
499 "for this system (tried: 1024x768, 800x600, "
511 "splash: this system does not support graphics, using fallback "
513 return handleNoSplash();
516 Framebuffer* pParentFramebuffer = g_GraphicsParams.providerResult.pFramebuffer;
518 g_Width = pParentFramebuffer->getWidth();
519 g_Height = pParentFramebuffer->getHeight();
521 g_pFramebuffer = Graphics::createFramebuffer(pParentFramebuffer, 0, 0, g_Width, g_Height);
522 g_ColorFormat = g_pFramebuffer->getFormat();
524 g_pFramebuffer->
rect(0, 0, g_Width, g_Height, g_BackgroundColour, g_ColorFormat);
528 uint8_t* data = header_data;
529 g_pBuffer =
new uint8_t[width * height * 3];
530 for (
size_t i = 0; i < (width * height); i++)
531 HEADER_PIXEL(data, &g_pBuffer[i * 3]);
533 size_t origx = (g_Width - width) / 2;
534 size_t origy = (g_Height - height) / 3;
536 g_pFramebuffer->
draw(g_pBuffer, 0, 0, origx, origy, width, height, Graphics::Bits24_Bgr);
542 g_pBuffer =
new uint8_t[(FONT_WIDTH * FONT_HEIGHT * 3) * 256];
543 ByteSet(g_pBuffer, 0, (FONT_WIDTH * FONT_HEIGHT * 3) * 256);
547 for (
size_t character = 0; character < 255; character++) {
549 for (
size_t row = 0; row < FONT_HEIGHT; row++) {
551 for (
size_t col = 0; col < FONT_WIDTH; col++) {
553 size_t fontRow = (character * FONT_HEIGHT) + row;
554 if (font_data[fontRow] & (1 << (FONT_WIDTH - 1 - col))) {
557 size_t bytesPerPixel = 3;
558 size_t bytesPerLine = FONT_WIDTH * bytesPerPixel;
559 size_t pixelOffset = (fontRow * bytesPerLine) + (col * bytesPerPixel);
560 size_t bufferOffset = pixelOffset;
562 uint32_t* p = adjust_pointer<uint8_t, uint32_t>(g_pBuffer, bufferOffset);
563 *p = g_ForegroundColour;
570 g_pFramebuffer->
createBuffer(g_pBuffer, Graphics::Bits24_Rgb, FONT_WIDTH, FONT_HEIGHT * 256);
573 g_ProgressX = (g_Width / 2) - 200;
575 g_ProgressY = (g_Height / 3) * 2;
579 g_LogBoxY = (g_Height / 4) * 3;
581 g_LogH = g_Height - g_LogBoxY;
593 centerStringAt(
"Please wait, Pedigree is loading...", g_Width / 2,
594 g_ProgressY - (FONT_HEIGHT * 3));
598 centerStringAt(
"< Kernel Log >", g_LogW / 2,
599 g_LogBoxY - 2 - (FONT_HEIGHT / 2) - FONT_HEIGHT);
601 "(you can push ESCAPE to view the kernel log, and again to make the "
602 "log fill the screen)",
603 g_LogW / 2, g_LogBoxY - 2 - (FONT_HEIGHT / 2));
609 g_pFramebuffer->
rect(g_ProgressX - 2, g_ProgressY - 2, g_ProgressW + 4, g_ProgressH + 4,
610 g_ProgressBorderColour, g_ColorFormat);
611 g_pFramebuffer->
rect(g_ProgressX - 1, g_ProgressY - 1, g_ProgressW + 2, g_ProgressH + 2,
612 g_BackgroundColour, g_ColorFormat);
615 g_pFramebuffer->
redraw(0, 0, g_Width, g_Height,
true);
622 g_BootProgressUpdate = &progress;
632 g_NoGraphics =
false;
634 char* cmdline = g_pBootstrapInfo->getCommandLine();
637 for (
auto it = cmds.begin(); it != cmds.end(); it++) {
643 }
else if (
cmd ==
String(
"splash=image")) {
647 }
else if (!StringCompareN(
cmd.cstr(),
"video=", 6)) {
648 valid = parseVideoMode(
cmd.cstr() + 6);
649 }
else if (!StringCompareN(
cmd.cstr(),
"splash-background=", 18)) {
650 valid = parseColour(
cmd.cstr() + 18, g_BackgroundColour);
651 }
else if (!StringCompareN(
cmd.cstr(),
"splash-foreground=", 18)) {
652 valid = parseColour(
cmd.cstr() + 18, g_ForegroundColour);
653 }
else if (!StringCompareN(
cmd.cstr(),
"splash-border=", 14)) {
654 valid = parseColour(
cmd.cstr() + 14, g_ProgressBorderColour);
655 }
else if (!StringCompareN(
cmd.cstr(),
"splash-fill=", 12)) {
656 valid = parseColour(
cmd.cstr() + 12, g_ProgressColour);
659 WARNING(
"splash: ignoring invalid boot option " <<
cmd);
665 return handleNoSplash();
667 return handleSplash();
671static void destroy() {
682 g_BootProgressUpdate = 0;
685MODULE_INFO(
"splash", &init, &destroy);
688MODULE_OPTIONAL_DEPENDS(
"gfx-deps");
EXPORTED_PUBLIC void write(T &str, Colour foreColour, Colour backColour)
virtual bool getCurrentScreenMode(ScreenMode &sm)
virtual bool setScreenMode(ScreenMode sm)
virtual Graphics::Buffer * createBuffer(const void *srcData, Graphics::PixelFormat srcFormat, size_t width, size_t height, uint32_t *pPalette=0)
virtual void blit(Graphics::Buffer *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, bool bLowestCall=true)
virtual void copy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h, bool bLowestCall=true)
virtual void draw(void *pBuffer, size_t srcx, size_t srcy, size_t destx, size_t desty, size_t width, size_t height, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
virtual void destroyBuffer(Graphics::Buffer *pBuffer)
virtual void rect(size_t x, size_t y, size_t width, size_t height, uint32_t colour, Graphics::PixelFormat format=Graphics::Bits32_Argb, bool bLowestCall=true)
void redraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL, bool bChild=false)
EXPORTED_PUBLIC bool removeCallback(LogCallback *pCallback)
static EXPORTED_PUBLIC Log & instance()
EXPORTED_PUBLIC bool installCallback(LogCallback *pCallback, bool bSkipBacklog=false)
bool tryAcquire(size_t n=1)
virtual bool provides(Type service)
Service * getService(const String &serviceName)
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
void callback(const LogCord &cord, bool=true)
A vector / dynamic array.