New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NTOS:INBV] Implement rotation bar for boot screen #194
Conversation
A fourth TODO would be to have this appearance set via a registry key or any other sort of setting :) |
ntoskrnl/inbv/inbv.c
Outdated
@@ -768,6 +775,7 @@ INIT_FUNCTION | |||
DisplayBootBitmap(IN BOOLEAN TextMode) | |||
{ | |||
PVOID Header = NULL, Footer = NULL, Screen = NULL; | |||
UCHAR Buffer[128]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this 128-byte value comes from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since bar bitmap is 22x9 and 4bpp (hardcoded, yes), minimum value would be 22 * 9 * (4 bpp / 8 bits) = 99
, but I made it a bit larger to reserve.
Also I don't know whether InbvScreenToBufferBlt
uses some headers for the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It calls VidScreenToBufferBlt
(in bootvid.dll).
By looking at the code, this function seems to use Delta * Height
bytes in the buffer (delta is the last parameter of the function). I don't personally completely understand yet what this Delta
is for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scan lines in a bitmap get aligned (to a 4-byte boundary IIRC), so the scanline width can be different from the image width. Delta is likely the scanline width.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yagoulas commented in IRC:
it looks like delta is the width of the source bitmap
and I gues this would be used when you want to paint only a part of the marqee when it has reached the right part of the scrollbar and starts disappearing
this would be a case when width<Delta
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hypothesis of the scanline width makes sense, and this would explain the value of "4" (or "8", don't remember) seen in other places where this function is called, and where the used Delta is completely different than the specified Width.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so 24 * 9 * (4/8) = 108
, still should be ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, UCHAR Buffer[24 * 9 * 4 / 8];
? ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, and it used in three places... 😆
ntoskrnl/inbv/inbv.c
Outdated
{ | ||
ULONG X, Y, Iteration, Index, Total = 18; | ||
UCHAR Buffer[128]; | ||
#ifndef INBV_ROTBAR_IMPLEMENTED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this you could do:
#ifdef INBV_ROTBAR_IMPLEMENTED
VOID NTAPI ... InbvRotBarInit(VOID)
{
// The implementation
return;
}
#else
VOID NTAPI ... InbvRotBarInit(VOID)
{
return;
}
#endif
or even, just have the function defined in that case and calling in the main code only between #ifdef INBV_ROTBAR_IMPLEMENTED
guards ?
ntoskrnl/inbv/inbv.c
Outdated
if (RotBarSelection != RB_SQUARE_CELLS) | ||
return; | ||
|
||
/* This function needs to be in system thread, but it's not yet */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean "needs to be called by system thread" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part of code should be in while ()
loop instead of for
, and run in context of a separate thread.
For now it's executed sequentially, so the loop is limited to 6 rotations (for demonstration).
ntoskrnl/inbv/inbv.c
Outdated
@@ -920,8 +930,14 @@ DisplayBootBitmap(IN BOOLEAN TextMode) | |||
#endif | |||
|
|||
#ifdef INBV_ROTBAR_IMPLEMENTED | |||
/* Save previous screen pixels to buffer */ | |||
InbvScreenToBufferBlt(Buffer, 0, 0, 22, 9, 24); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably can move this whole block inside the if (Bar)
since saving restoring is unnecessary otherwise?
ntoskrnl/inbv/inbv.c
Outdated
@@ -932,18 +948,67 @@ DisplayBootBitmap(IN BOOLEAN TextMode) | |||
} | |||
|
|||
#ifdef INBV_ROTBAR_IMPLEMENTED | |||
/* Hide simple progress bar if not used */ | |||
if (RotBarSelection != RB_PROGRESS_BAR) | |||
ShowProgressBar = FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Braces around all blocks please.
You probably have neither file system nor registry available during this part of boot, so making it user-configurable is not exactly trivial. |
cd56569
to
08702a7
Compare
ntoskrnl/inbv/inbv.c
Outdated
@@ -768,6 +775,7 @@ INIT_FUNCTION | |||
DisplayBootBitmap(IN BOOLEAN TextMode) | |||
{ | |||
PVOID Header = NULL, Footer = NULL, Screen = NULL; | |||
UCHAR Buffer[128]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be placed inside a #ifdef INBV_ROTBAR_IMPLEMENTED
.
7d7ce5f
to
be981d8
Compare
You're right Thomas; actually it seems the best way would be:
|
Yes, and even the parameter would likely not work, since, as I said, no filesystem access! You might need to do something like compile the logo as a resource into a sys file, have freeldr load that as a boot driver and then pass a kernel command line argument to specify that driver's name. In which case you might as well have recompiled the kernel in the first place... Like I said, nontrivial :) |
I remember that we had the rotation bar early in 0.3.1 times (just when the current bootvid was checked in). It was a very buggy implementation, so someone shortly disabled it. Later, the current progress bar was added. Given that we have a progress bar that shows boot progress from 0 to 100%, I wonder what's the value of a less informative rotation bar? Just because XP does it? Well, Win2k had a progress bar too, and I preferred that :) I'm all for making our boot animation more exciting. However, that should be more than just replacing the progress bar. |
I think it's good to have some animation, because it shows that the system is not frozen. But it doesn't have to be XP's "marquee" bar. We could easily go the macOS way and show an actual spinner/throbber animation, if showing a full blown boot animation (like vista+ do) would be too much without boot-time graphics support. A small throbber animation should be fairly easy to produce and implement, and not slower than the not-really-progress bar? |
Because I wasn't clear: I do agree with Colin that the existing progressbar should stay, I'm talking about an added thing to show that it's not frozen. |
Maybe some animantion that uses the progress bar like in Win7's progress bar? |
That may be too slow depending on how large the progressbar gets. The idea of the small rotating image or a spinner, is that the number of pixels redrawn each frame is relatively small (if the drawing code only writes the needed pixels), which is important due to having to poke the video memory directly since we don't have boot-time video support like NT6 does. EDIT: On second thought, if the XP-style animation was actually the highlight, contained in the "completed" area of a progressbar, that would work! |
Please notice this PR is not targeting to replace current progress bar (I like it too) but to bring up an ability to change its behaviour at compile time (or maybe at boot time later). When it will be finished, it would be simpler to create some other animations by reusing the code. |
be981d8
to
2839ba0
Compare
Rewrote part of drawing code, so now it properly renders appearing part from the left. 😉 Demonstration: https://webmshare.com/1WZNg |
2839ba0
to
e6556ac
Compare
This was correct, the pixels are stored in bytes inside 8-bit buffer, so the size should be Also I noticed that So there is only one step left - to make it run separately (in thread) along with boot loading process. @ThFabba do you know how to do that? |
About the locking thing, maybe there is a proper way to reorganize that (in your helper function) without the need to directly call the Vid* functions. |
I don't know if that's available at this point in the boot process, but normally to create a thread you would use PsCreateSystemThread, like here: |
I already fixed it (commented above), this video demo is a bit outdated already :) |
Directly calling the Vid* functions from inside Inbv seems correct -- in fact I'd say you probably should do it for VidBufferToScreenBlt as well. |
e6556ac
to
400a80c
Compare
Just for reference purposes, here is our (very) old animation procedure we used to have in bootvid: BootVidAnimationThread , before this module got rewritten. |
c872296
to
503c1b9
Compare
Code updated with @ThFabba's suggestions. |
ntoskrnl/inbv/inbv.c
Outdated
Status = PsCreateSystemThread(&ThreadHandle, | ||
SYNCHRONIZE, | ||
0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The '0' works OK.
ntoskrnl/inbv/inbv.c
Outdated
RB_ANIMATE, | ||
RB_STOP_ANIMATE, | ||
RB_STATUSMAX | ||
} ROT_BAR_STATUS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have better names for all these, just let us know!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe RBS_* ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good :)
503c1b9
to
223bc38
Compare
ntoskrnl/inbv/inbv.c
Outdated
{ | ||
/* Acquire the lock */ | ||
InbvAcquireLock(); | ||
LARGE_INTEGER Delay; // Specified in nanoseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not nanoseconds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh indeed, it's in hundreds of nanoseconds :) I'll fix the comments; the calculations/values used for Delay are however OK.
ntoskrnl/inbv/inbv.c
Outdated
LARGE_INTEGER Delay = {{0}}; | ||
|
||
// FIXME: This was added to suppress thread hanging | ||
KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still like to get rid of this before merging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@binarymaster, could you please check whether things work without the priority setting? I think they should.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I retested without this change, and found no difference. So this can be removed.
Interesting... rotation bar animation was implemented with 3 buffers for each square cell :) |
ntoskrnl/inbv/inbv.c
Outdated
@@ -161,7 +161,7 @@ BootLogoFadeIn(VOID) | |||
LPRGBQUAD Palette = (LPRGBQUAD)(PaletteBitmapBuffer + sizeof(BITMAPINFOHEADER)); | |||
ULONG Iteration, Index, ClrUsed; | |||
|
|||
LARGE_INTEGER Delay; // Specified in nanoseconds | |||
LARGE_INTEGER Delay = {{0}}; // Specified in hundreds of nanoseconds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this needs to be initialized in all places, or it have only one field (QuadPart)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure it zeroes out the Delay because when the while() loop is run for the first time, KeDelayExecutionThread is called with a valid delay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, specifying an initializer for any member of a struct, union, or array means the whole object will be initialized.
On an unrelated note, this comment seems completely unnecessary. The unit is obvious to anyone familiar with kernel programming, and anyone else needs to read the documentation for KeDelayExecutionThread anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, removed.
ntoskrnl/inbv/inbv.c
Outdated
break; | ||
} | ||
|
||
if (PltRotBarStatus >= RBS_STATUS_MAX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no way this can happen, right? So an ASSERT should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ASSERT.
*/ | ||
typedef enum _ROT_BAR_STATUS | ||
{ | ||
RBS_FADEIN = 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to make this distinct from 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really, why isn't this just a boolean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally (and as the original code -- before @binarymaster's patch -- also suggested via the value of "PltRotBarStatus"), this looked like it was designed as a "command" variable for the animation thread to know what to do "next", like, first, do the palette fading-in, then the rotation, then stop (in the usual order, but you can also choose to blank the screen again, then redo a fading in etc...).
In the current code the fading-in is done before starting the animation thread; I was wondering whether it could be nice instead to move it in the animation thread where that PltRotBarStatus variable would then make better sense (I didn't do the move as you can see).
But perhaps we can also do the way of the old bootvid code (see my link above), where the animation thread always do "fading in" first, then bar rotation, and thus the PltRotBarStatus would just become a Boolean "start / stop".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer leave this variable as is...
981c83a
to
29a8b40
Compare
Judging from your latest demonstration video, you are using the rotation bar bitmap from Windows Server 2003. This must be changed to something custom should this PR be merged. Nevertheless, I still prefer a boot screen with a progress bar that shows actual progress over a rotating one. |
No, I haven't used it. I even didn't modify it (see diff), this bitmap is slightly different and currently in master branch.
Have you tried building my PR branch? 😈 There's already a different animation, which also stated in TODO list. 😉 |
29a8b40
to
63c765a
Compare
https://gfycat.com/EvergreenBrilliantCoelacanth New GIF demo ;) |
@ThFabba and @ColinFinck , is everything OK so that we can proceed to a squash-and-merge? |
63c765a
to
215033b
Compare
CORE-10327 #resolve
- Use KeDelayExecutionThread() instead of KeStallExecutionProcessor(). - Fix magic values and add comments. - Fix structure name.
215033b
to
071685d
Compare
Rearranged commits for rebase and merge (two commits without squash), I think it would be better. |
* Update openoffice.txt * Update SHA1 hash
Purpose
Implement a rotation bar for bootup screen! 😃
Inspired by JIRA issue: CORE-14101
Fixes issue: CORE-10327
Proposed changes
It adds implementation of bootup rotation bar, like in Windows XP.
Also implemented a rotation line animation which would be showed along with classic progress bar.
TODO
Any help is appreciated.
0x0000007E
and fix it0x0000007E
and fix it