Skip to content

Add DPI awareness and guest process launch - #10

Merged
AdvDebug merged 2 commits into
mainfrom
brovan-dpi-and-multiprocess
Jul 28, 2026
Merged

Add DPI awareness and guest process launch#10
AdvDebug merged 2 commits into
mainfrom
brovan-dpi-and-multiprocess

Conversation

@AdvDebug

@AdvDebug AdvDebug commented Jul 27, 2026

Copy link
Copy Markdown
Owner

DPI awareness

The emulator gave every program a screen of 96 DPI. It also made the host window with no DPI awareness. A program that asks for a different DPI got the wrong screen size and a window that is not sharp.

The emulator now reads the DPI awareness of the program. It reads it from the application manifest in the image, from an external manifest file, or from the NtUserSetProcessDpiAwarenessContext system call.

user32 does not ask the kernel for most DPI values. It calculates them from a packed value in the CLIENTINFO block of the thread and in the window structure. The emulator writes this value into the two locations. If it does not, the program reads one DPI from user32 and a different DPI from the system calls.

The emulator gives the same awareness to the host window. An aware program gets a window in true pixels. An unaware program keeps the window that the desktop manager makes larger for it.

The emulator also sets the composited flag in the desktop data. Without this flag, user32 uses a different code path. That path gives 96 DPI to a program that is aware.

Guest process launch

A guest process could not start a different program. The emulator did not have the NtCreateUserProcess system call.

The emulator now starts a second Brovan for each new guest process. One guest process is one host process. The window manager, the Vulkan device, the scheduler and the caches are global to a process. Two guests in one emulator need a process identity in all of them.

The parent sends the image path, the command line and the directory to the child. It encodes these values with base64. Without base64, the host command line divides the values and joins them again. A value with a quotation mark or a space does not stay correct.

Session registry

The Brovan instances of one session share a table in a memory-mapped file. Each instance writes one row. An instance that must stop a different guest process writes a request into the row of that process. The owner of the row reads the request and stops itself. This is the only correct method. The memory of that process is in a different host process.

The emulator counts the rows before it starts a child. It permits a maximum of six guest processes in one session.

New options

--cwd <dir> sets the directory in which the program starts.

--guest-cmdline <s> sets the command line of the program. The two options also accept a value in the form "base64:<value>".

# DPI awareness

The emulator gave every program a screen of 96 DPI. It also made the host
window with no DPI awareness. A program that asks for a different DPI got
the wrong screen size and a window that is not sharp.

The emulator now reads the DPI awareness of the program. It reads it from
the application manifest in the image, from an external manifest file, or
from the NtUserSetProcessDpiAwarenessContext system call.

user32 does not ask the kernel for most DPI values. It calculates them
from a packed value in the CLIENTINFO block of the thread and in the
window structure. The emulator writes this value into the two locations.
If it does not, the program reads one DPI from user32 and a different DPI
from the system calls.

The emulator gives the same awareness to the host window. An aware program
gets a window in true pixels. An unaware program keeps the window that the
desktop manager makes larger for it.

The emulator also sets the composited flag in the desktop data. Without
this flag, user32 uses a different code path. That path gives 96 DPI to a
program that is aware.

# Guest process launch

A guest process could not start a different program. The emulator did not
have the NtCreateUserProcess system call. DELTARUNE stopped at its menu
for this reason. The game starts a new process when you select a chapter.

The emulator now starts a second Brovan for each new guest process. One
guest process is one host process. The window manager, the Vulkan device,
the scheduler and the caches are global to a process. Two guests in one
emulator need a process identity in all of them. The host operating system
gives this isolation at no cost.

The parent sends the image path, the command line and the directory to the
child. It encodes these values with base64. Without base64, the host
command line divides the values and joins them again. A value with a
quotation mark or a space does not stay correct.

# Session registry

The Brovan instances of one session share a table in a memory-mapped file.
Each instance writes one row. An instance that must stop a different guest
process writes a request into the row of that process. The owner of the row
reads the request and stops itself. This is the only correct method. The
memory of that process is in a different host process.

The emulator counts the rows before it starts a child. It permits a maximum
of six guest processes in one session.

# New options

--cwd <dir> sets the directory in which the program starts.
--guest-cmdline <s> sets the command line of the program.
The two options also accept a value in the form "base64:<value>".
@AdvDebug

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dd672f4bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Brovan/Core/Emulation/OS/Windows/Process/GuestProcessLauncher.cs
Comment thread Brovan/Core/Emulation/OS/Windows/Process/NtCreateUserProcess.cs
Comment thread Brovan/Core/Emulation/OS/Windows/Process/GuestSessionRegistry.cs
Comment thread Brovan/Core/Emulation/OS/Windows/Process/NtReadVirtualMemory.cs Outdated
@AdvDebug

Copy link
Copy Markdown
Owner Author

Will fix it later

This change fixes several process-management edge cases in Windows emulation. Reused guest session slots now clear mailbox state before reassignment to prevent stale sequence numbers from being treated as new requests. Newly created user processes are added to `WinProcesses` so they are tracked consistently. `NtReadVirtualMemory` now writes `BytesRead` using the active pointer size instead of always 8 bytes, improving x86/x64 correctness. The main process PID is now initialized by adopting the host process ID when available, falling back to random generation only when needed.
@AdvDebug

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@AdvDebug

Copy link
Copy Markdown
Owner Author

Will do more tests on it today before merging it

@AdvDebug
AdvDebug merged commit 3289426 into main Jul 28, 2026
2 checks passed
@AdvDebug
AdvDebug deleted the brovan-dpi-and-multiprocess branch July 29, 2026 11:55
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.

1 participant