Skip to content

[console] VirtCon save/restore on graphics enter/exit#2671

Open
cpiker wants to merge 1 commit into
ghaerr:masterfrom
cpiker:console-vc-save
Open

[console] VirtCon save/restore on graphics enter/exit#2671
cpiker wants to merge 1 commit into
ghaerr:masterfrom
cpiker:console-vc-save

Conversation

@cpiker
Copy link
Copy Markdown

@cpiker cpiker commented May 3, 2026

This change allows someone to start a game on one virtual console and then return to text mode with all consoles' content preserved.

  • RAM-backed virtual consoles for small-memory video adapters:

    Re-enables CONFIG_CONSOLES_MAX (1-8). When the requested VC count exceeds the adapter's video RAM, heap buffers are allocated for backing VCs. If video memory is sufficient, this has no impact.

  • Console text preservation through video mode changes:

    The DCGET_GRAPH ioctl snapshots console text pages to heap; DCREL_GRAPH restores them and resets the CRTC start address.

    If VCs are RAM-backed, only the current console page is saved since background VCs already live on the heap. Page-flip mode must save every VC since graphics writes may destroy all text pages (e.g. CGA mode 4).

  • Why bundle:

    Bundled into one change-set because MDA cards didn't have more than one supported VC, and many MDA cards are actually Hercules graphics, which would use this feature. Since detecting Hercules is error-prone, using RAM buffers when the BIOS equipment word indicates MDA is the safe bet.

Alt-F1..F8 keybindings widened from F1..F4 to match the new VC upper bound.

Tested on Leading Edge Model D with both MDA and CGA monitors, 2 VCs each. 20+ graphics entry/exit cycles per config; text preserved across every transition in each console; no memory leaks.

This change allows someone to start a game on one virtual console
and then return to text mode with all consoles' content preserved.

  * RAM-backed virtual consoles for small-memory video adapters:

    Re-enables CONFIG_CONSOLES_MAX (1-8). When the requested VC
    count exceeds the adapter's video RAM, heap buffers are
    allocated for backing VCs. If video memory is sufficient,
    this has no impact.

  * Console text preservation through video mode changes:

    The DCGET_GRAPH ioctl snapshots console text pages to heap;
    DCREL_GRAPH restores them and resets the CRTC start address.

    If VCs are RAM-backed, only the current console page is saved
    since background VCs already live on the heap. Page-flip mode
    must save every VC since graphics writes may destroy all
    text pages (e.g. CGA mode 4).

  * Why bundle:

    Bundled into one change-set because MDA cards didn't have
    more than one supported VC, and many MDA cards are actually
    Hercules graphics, which would use this feature. Since
    detecting Hercules is error-prone, using RAM buffers when
    the BIOS equipment word indicates MDA is the safe bet.

Alt-F1..F8 keybindings widened from F1..F4 to match the new VC
upper bound.

Tested on Leading Edge Model D with both MDA and CGA monitors,
2 VCs each. 20+ graphics entry/exit cycles per config; text
preserved across every transition in each console; no memory leaks.
@ghaerr
Copy link
Copy Markdown
Owner

ghaerr commented May 3, 2026

Hello @cpiker,

Nicely done. Do these enhancements allow running Nano-X and switching back to text mode, restoring the previous text display? If so, this is a major enhancement to usability of ELKS.

Nice idea using off-card memory for the video buffers, I wouldn't have thought of that idea. I am wondering a bit whether it might be better to allocate out of main memory rather than the kernel heap; some systems may be pretty tight on kernel heap free space. I haven't had time to fully review your code yet, the VC allocation only occurs once and during kernel init, right? That decreases any heap checkerboarding that might otherwise occurring using either heap.

allows someone to start a game on one virtual console and then return to text mode

Which games have you tested with this mod? We will likely (separately) also have to deal with the problem of notifying the graphics-drawing program to stop drawing or possibly not be scheduled for any execution while text mode is active. I need to think a bit more about how exactly that should work. On graphics restoration, a signal or another mechanism could be sent to the process to tell it to regenerate the graphic display.

Thank you!

@cpiker
Copy link
Copy Markdown
Author

cpiker commented May 3, 2026

Running Nano-X (or other graphics) and then switching back to text mode is exactly the operation I'm trying to support. Mostly I had in mind short lived programs such as image viewers, games, etc. but I guess this could be useful to full desktop environments too.

I was nervous about using any extra memory, so allocation only happens in two instances:

  1. You ask for more VCs then the video card can support. This allocation happens once at init and there is a message on the console indicating that a RAM buffer is in use. For my case of using 2 VCs with an MDA monitor it's only an 8K hit. The same concept applies if you ask for 8 VCs on a CGA card.

  2. When switching to graphics mode the current VC memory is saved and then restored on switch out. This is a temporary buffer, in use only until DCREL_GRAPH ioctl is called. To avoid using too much temporary memory on machines that mostly run a Nano-X desktop, dropping the number of VCs to 2 might be a good idea since each extra VC eats about 4K.

I wanted this to be a no-ram-cost extension to current capabilities as much as possible, so if you never run a graphical program and have at least a CGA card, there is no effect on memory usage.

I didn't test with any games per-se because I noticed this issue before I started porting anything to use the DCGET_GRAPH ioctl. Instead I made a test program that exercised:

  • Pure MDA mode (no graphics)
  • CGA mode (goes to CGA mode 4 then back)
  • LEMD mode (sets up enhanced video on a Leading Edge Model D)

It basically switched, drew a test pattern, and switched back so that I could make sure the text restored correctly.

A caveat: I haven't setup any hardware to provide a dual-monitor testbed so currently CONFIG_CONSOLE_DUAL disables all save/restore functionality. I can work on extending this to dual-monitor cases in a subsequent patch if you like.

Can you provide guidance on using main memory instead of the kernel heap, especially with a link to example source code? I'm new and thought I was supposed to use the kernel heap. Happy to make changes.

@ghaerr
Copy link
Copy Markdown
Owner

ghaerr commented May 3, 2026

Running Nano-X (or other graphics) and then switching back to text mode is exactly the operation I'm trying to support.

I didn't test with any games per-se

Given that your code is well written, and this new capability could be very beneficial for those wanting to switch between Nano-X and other graphical programs, I'm inclined to want to accept the PR now, mostly as-is, rather then waiting until after v0.9.1 is released. As you may have read, I botched the Nano-X binary in the v0.9.0 release and running nxstart crashes the system. This is now fixed, and then a bunch of easy fixable kernel bugs were identified with some AI analyses, so those fixes went in too. I don't think there's time to get graphics/text mode switching working well immediately and I was thinking of releasing v0.9.1 very soon.

That said, in order to get this first step committed, I would like to have all its features turned off by default, so that there is no need for testing Nano-X compatibility at this time, including any memory allocations of any kind. The code would be included, and you could continue to experiment with actually running the various games/graphics/nano-x included on the distribution(s), and we can come up with a mechanism that would allow graphics programs to coexist with a switchable text/graphics console.

To do this, I would suggest making the following mods right now, after which I can commit:

  • Set default VC's (CONFIG_CONSOLES_MAX) to 3.
  • Set VC_GRAPH_SAVE_RESTORE to 0.
  • Possibly ifdef new struct console members and the other init code with VC_GRAPH_SAVE_RESTORE (or another) define so that the extra code is not included when not used.

Other small issues are to be consistent with #if vs #ifdef VC_GRAPH_SAVE_RESTORE - the ifdef is incorrect when set to 0, so just use #if throughout.

The kernel is getting dangerously short on both text and data segment space, so I'm leaning towards less warning messages etc. long term. However, during development these are quite useful so we can leave them in for now. This can be discussed more fully later. The fact that we're almost out of near text space in the kernel may also mandate options to not include features (possibly like this) which may not be wanted by all users. That can also be sorted out later, and I will look further into how much space is left after commit, but another reason why it would be temporarily nice to have a way to turn off the entire new feature so close to releasing v0.9.1.

When switching to graphics mode the current VC memory is saved and then restored on switch out. This is a temporary buffer, in use only until DCREL_GRAPH ioctl is called. To avoid using too much temporary memory on machines that mostly run a Nano-X desktop, dropping the number of VCs to 2 might be a good idea since each extra VC eats about 4K.

These are some of the reasons I'm thinking of turning off the feature until v0.9.1 is released. I don't want to change the default VC numbers or possibly have ELKS kernel run out of memory when running nano-X until more is known about how the system operates. Version 0.9.0 provides some big enhancements to Nano-X so it is a priority for v0.9.1 to make sure it's working.

I wanted this to be a no-ram-cost extension to current capabilities as much as possible, so if you never run a graphical program and have at least a CGA card, there is no effect on memory usage.

I agree and nice idea, for sure. But memory is still allocated just during the switch to text mode, right? The text mode buffer(s) always have to be copied since a graphics program may use it.

I can work on extending this to dual-monitor cases in a subsequent patch if you like.

Let's not worry about that until getting the basic text/graphics switching code working with the DCSET_ and DCREL_ ioctls. (BTW, you may have noticed that the Nano-X driver microwindows/src/drivers/scr_vga.c already has commented out ioctl's for this. However, they are currently designed to disallow switching to text mode once started - also not implemented).

All-in-all, this is a very nice first step, thank you for your work :)

@ghaerr
Copy link
Copy Markdown
Owner

ghaerr commented May 3, 2026

Regarding the business of how Microwindows/Nano-X actually works with text/graphics mode switching on Linux, you might want to look at microwndows/src/drivers/vtswitch.c. This code is part of the user-space driver which starts and stops graphics drawing in the Nano-X server. I don't think we necessarily want to go this route of complexity, but the code does show some of the issues involved, such as programs being able to query the console switch state, as well as refusing a switch, etc. All of this and more will have to be considered for what might want to happen on ELKS. As I said earlier, I think possibly a much simpler approach of literally un-scheduling the graphics app from running, and then signaling a way to redraw the graphics will be much superior than the mechanism vtswitch.c and Linux Nano-X use.

All of this can be discussed in more detail later.

@cpiker
Copy link
Copy Markdown
Author

cpiker commented May 4, 2026

I don't think there's time to get graphics/text mode switching working well immediately and I was thinking of releasing v0.9.1 very soon.

Could you expand on 'very soon'? Are you thinking tomorrow, next weekend? Tomorrow is a heavy work day for me so the earliest I could update the PR would be late in the evening and more realistic is late Tues night.

To do this, I would suggest making the following mods right now, after which I can commit:

  • Set default VC's (CONFIG_CONSOLES_MAX) to 3.
  • Set VC_GRAPH_SAVE_RESTORE to 0.
  • Possibly ifdef new struct console members and the other init code with VC_GRAPH_SAVE_RESTORE (or another) define so that the extra code is not included when not used.

Other small issues are to be consistent with #if vs #ifdef VC_GRAPH_SAVE_RESTORE - the ifdef is incorrect when set to 0, so just use #if throughout.

Sure I can do that.

I agree and nice idea, for sure. But memory is still allocated just during the switch to text mode, right? The text mode buffer(s) always have to be copied since a graphics program may use it.

You're right. Currently the feature as implemented always saves the console state when something grabs the graphics lock. Even setting CONFIG_CONSOLES_MAX = 1 causes 4K to be allocated.

All-in-all, this is a very nice first step, thank you for your work :)

You're more than welcome. ELKS is a gem, happy to contribute where I can.

@cpiker
Copy link
Copy Markdown
Author

cpiker commented May 5, 2026

I've worked through the PR update and am almost there. Need to run a couple hardware tests first. Should be done tomorrow night.

@ghaerr
Copy link
Copy Markdown
Owner

ghaerr commented May 5, 2026

I've worked through the PR update and am almost there.

No worries - I think I'll publish v0.9.1 in the next day or so and then commit this afterwards. It'll be better to not worry about breaking v0.9.1, so no need to rush.

@cpiker
Copy link
Copy Markdown
Author

cpiker commented May 5, 2026

Sounds good. Say if you could hold off on merging this even after v0.9.1 is out the door for just a little bit I'd appreciate it.

I realized that my changes to allow up to 8 VC's were based off old Configure.help text that didn't really go with the mentality of the rest of the code in the master branch, so I backed that out to make a smaller change-set. Would like to amend the PR before it's merged anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants