Skip to content

WpfGfx: Fix headless RenderTargetBitmap rendering#11467

Open
etvorun wants to merge 1 commit intodotnet:mainfrom
etvorun:fix/render-target-bitmap-headless
Open

WpfGfx: Fix headless RenderTargetBitmap rendering#11467
etvorun wants to merge 1 commit intodotnet:mainfrom
etvorun:fix/render-target-bitmap-headless

Conversation

@etvorun
Copy link

@etvorun etvorun commented Feb 18, 2026

Summary

Fixes a rendering gap where RenderTargetBitmap could produce blank output when no display devices are attached.

What changed

  • Added canRenderWithoutDisplayDevices to compose pipeline signatures.
  • Updated CComposition::ProcessComposition to allow rendering when this flag is set.
  • Enabled the flag only for the synchronous UI-thread compose path used by RenderTargetBitmap-style rendering.
  • Kept regular partition-thread rendering behavior unchanged by passing false there (compat switch behavior remains available).

Why

The composition pass may skip rendering when display state is invalid. For the UI-thread bitmap rendering path, this caused blank image output in headless/disconnected environments. The change provides a targeted override for that path without broadening default behavior.

Validation

Manual-only validation by repository owner.

Fixes #11466

Microsoft Reviewers: Open in CodeFlow

- Preserve existing default partition-thread render behavior

- Allow UI-thread synchronous compose path to render without display devices

- Keep compatibility switch behavior unchanged
@etvorun etvorun requested review from a team and Copilot February 18, 2026 23:10
@dotnet-policy-service dotnet-policy-service bot added the PR metadata: Label to tag PRs, to facilitate with triage label Feb 18, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a headless rendering gap in WpfGfx where RenderTargetBitmap-style synchronous (UI-thread) composition could produce blank output when no display devices are available, by threading an explicit “render even without displays” flag through the compose pipeline.

Changes:

  • Added a canRenderWithoutDisplayDevices parameter to the Partition::Compose/CComposition::Compose/CComposition::ProcessComposition call chain.
  • Updated CComposition::ProcessComposition to allow a render pass when this flag is set (in addition to the existing compatibility switch).
  • Enabled the flag only for the same-thread (UI-thread) present path; partition-thread rendering continues to pass false.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/partitionthread.cpp Passes false for regular partition-thread rendering and documents the AppContext switch behavior.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/partition.h Updates Partition::Compose signature to accept the new flag.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/connectioncontext.cpp Passes true for same-thread synchronous compose used by RenderTargetBitmap-style rendering.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/composition.h Threads the new flag through CComposition::Compose and ProcessComposition declarations.
src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/composition.cpp Uses the new flag to override render-pass skipping when display state is invalid.
Comments suppressed due to low confidence (1)

src/Microsoft.DotNet.Wpf/src/WpfGfx/core/uce/composition.cpp:654

  • In the WGXERR_DISPLAYSTATEINVALID path, NotifyDisplaySetChange expects the invalid flag (true when the display set is invalid). Passing doRenderPass here appears inverted relative to the comment: when canRenderWithoutDisplayDevices is true, we likely want to lie to targets that the display set is valid (invalid = false) so they don't release resources/invalidate; when doRenderPass is false we want invalid = true to notify targets of the invalid display set. Consider passing !doRenderPass (or an explicit invalidDisplaySet variable) instead of doRenderPass.
        // and notify any listeners that display set is not valid
        // If the UI thread has requested that we try to render despite this, 
        // then override and lie to listeners that displays are valid.
        IFC(m_pRenderTargetManager->NotifyDisplaySetChange(doRenderPass, displayCount));
        GetVisualCacheManagerNoRef()->NotifyDeviceLost();

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


MIL_THR(pServerEntry->pCompDevice->Compose(&fPresentNeeded));
// So far this method is used only to synchronously present on managed UI
// thread when calling RenderTargetBitmap.Render or alike. This can happen
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Grammar nit in the new comment: "RenderTargetBitmap.Render or alike" is awkward/incorrect English. Consider changing to "RenderTargetBitmap.Render or similar" (or "and similar APIs").

Suggested change
// thread when calling RenderTargetBitmap.Render or alike. This can happen
// thread when calling RenderTargetBitmap.Render or similar APIs. This can happen

Copilot uses AI. Check for mistakes.

// This code path is for regular WPF rendering. By default we do not allow
// rendering without display devices being present. App authors can still
// allow that with following switch in their app config file:
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Grammar nit in the new comment: "allow that with following switch" reads like a typo. Consider "allow that with the following switch" for clarity.

Suggested change
// allow that with following switch in their app config file:
// allow that with the following switch in their app config file:

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[WpfGfx] RenderTargetBitmap can produce blank output in headless sessions

2 participants