-
Notifications
You must be signed in to change notification settings - Fork 8.5k
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
Eliminate the IRenderTarget interface #12568
Conversation
Note that this is going to conflict with PR #12561, but it shouldn't be hard to resolve once that's merged. |
e55a7b1
to
a5cc853
Compare
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 think this is a fantastic step forward in cutting things down. Let's do this.
_pThread->EnablePainting(); | ||
// When the renderer is constructed, the initial viewport won't be available yet, | ||
// but once EnablePainting is called it should be safe to retrieve. | ||
_viewport = _pData->GetViewport(); |
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.
Should this throw intentionally now if _pData
is null given that it's not checked in the constructor anymore? Now it's implicitly crashing if someone did it wrong instead.
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 don't think it's worth it. Either way it's not going to run, so it's not like it makes any real difference. With a null pointer dereference it'll stop straight away in the debugger, while a throw will silently shut down and you have to look for a log entry to find out what happened. And there's no chance of shipping with a bug like that, so a cleaner shutdown isn't going to benefit the users.
Also, if we really do want to add a null check, this isn't the only place we'd need to put it, because it's possible to be dereferenced earlier than this. To be really "safe", we'd be putting null checks everywhere, and that just feels like pointless bloat.
@@ -214,6 +214,16 @@ const SCREEN_INFORMATION& CONSOLE_INFORMATION::GetActiveOutputBuffer() const | |||
return *pCurrentScreenBuffer; | |||
} | |||
|
|||
void CONSOLE_INFORMATION::SetActiveOutputBuffer(SCREEN_INFORMATION& screenBuffer) | |||
{ | |||
if (pCurrentScreenBuffer) |
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.
Aha I was wondering how you were going to manage that. Makes sense.
} | ||
|
||
NTSTATUS Status = SetUpConsole(&p->ConsoleInfo, p->TitleLength, p->Title, p->CurDir, p->AppName); |
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.
Given that you cannot see how g.pRender
is a dependency of SetUpConsole
now... we should perhaps leave a comment specifying that this has to be the order of them because setting up the console will go look it up and it shouldn't be reordered carelessly.
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, that's a good point. I've added some comments here now.
src/host/srvinit.cpp
Outdated
return Status; | ||
} | ||
|
||
// Allow the renderer to paint. |
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.
Or clarify further "Allow it to paint after the rest of the console has been hooked up."
I'm sorry, we made IRenderTarget slightly worse in #12358. We're trying to make sure accessibility is buttoned up for the 1.12 inbox release (for Windows 11 x2 (not a marketing name)), and I had to choose to merge that one instead of this one into main. I know that complicates this PR. |
No problem. It's wasn't a big deal to merge, and I suspect it could have been a lot worse going in the other direction. |
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.
On one hand: I'm a bit sad that the nice layering I had done three years ago to have the TextBuffer lib totally independent of the Renderer lib is now gone. On the other hand, I totally get why, and after 2+ years of the Terminal, it's clear why we never needed that in the first place.
Like 90% of this was just test fixes so the review really wasn't so bad.
Hello @lhecker! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
🎉 Handy links: |
Summary of the Pull Request
The purpose of the
IRenderTarget
interface was to support the conceptof multiple buffers in conhost. When a text buffer needed to trigger a
redraw, the render target implementation would be responsible for
deciding whether to forward that redraw to the renderer, depending on
whether the buffer was active or not.
This PR instead introduces a flag in the
TextBuffer
class to trackwhether it is active or not, and it can then simply check the flag to
decide whether it needs to trigger a redraw or not. That way it can work
with the
Renderer
directly, and we can avoid a bunch of virtual callsfor the various redraw methods.
PR Checklist
where discussion took place: Can we get rid of the IRenderTarget interface? #12551
Detailed Description of the Pull Request / Additional comments
Anywhere that had previously been getting an
IRenderTarget
from theTextBuffer
class in order to trigger a redraw, will now just call theTriggerRedraw
method on theTextBuffer
class itself, since that willhandle the active check which used to be the responsibility of the
render target. All the redraw methods that were in
IRenderTarget
arenow exposed in
TextBuffer
instead.For this to work, though, the
Renderer
needed to be available beforethe
TextBuffer
could be constructed, which required a change in theconhost initialization order. In the
ConsoleInitializeConnectInfo
function, I had to move the
Renderer
initialization up so it could beconstructed before the call to
SetUpConsole
(which initializes thebuffer). Once both are ready, the
Renderer::EnablePainting
method iscalled to start the render thread.
The other catch is that the renderer used to setup its initial viewport
in the constructor, but with the new initialization order, the viewport
size would not be known at that point. I've addressed that problem by
moving the viewport initialization into the
EnablePainting
method,since that will only be called after the buffer is setup.
Validation Steps Performed
The changes in architecture required a number of tweaks to the unit
tests. Some were using a dummy
IRenderTarget
implementation which nowneeded to be replaced with a full
Renderer
(albeit with mostly nullparameters). In the case of the scroll test, a mock
IRenderTarget
wasused to track the scroll delta, which now had to be replaced with a mock
RenderEngine
instead.Some tests previously relied on having just a
TextBuffer
but without aRenderer
, and now they require both. And tests that were constructingthe
TextBuffer
andRenderer
themselves had to be updated to use thenew initialization order, i.e. with the renderer constructed first.
Semantically, though, the tests still essentially work the same way as
they did before, and they all still pass.