WpfGfx: Fix headless RenderTargetBitmap rendering#11467
WpfGfx: Fix headless RenderTargetBitmap rendering#11467etvorun wants to merge 1 commit intodotnet:mainfrom
Conversation
- Preserve existing default partition-thread render behavior - Allow UI-thread synchronous compose path to render without display devices - Keep compatibility switch behavior unchanged
There was a problem hiding this comment.
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
canRenderWithoutDisplayDevicesparameter to thePartition::Compose/CComposition::Compose/CComposition::ProcessCompositioncall chain. - Updated
CComposition::ProcessCompositionto 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,
NotifyDisplaySetChangeexpects theinvalidflag (true when the display set is invalid). PassingdoRenderPasshere appears inverted relative to the comment: whencanRenderWithoutDisplayDevicesis true, we likely want to lie to targets that the display set is valid (invalid = false) so they don't release resources/invalidate; whendoRenderPassis false we wantinvalid = trueto notify targets of the invalid display set. Consider passing!doRenderPass(or an explicitinvalidDisplaySetvariable) instead ofdoRenderPass.
// 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 |
There was a problem hiding this comment.
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").
| // thread when calling RenderTargetBitmap.Render or alike. This can happen | |
| // thread when calling RenderTargetBitmap.Render or similar APIs. This can happen |
|
|
||
| // 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: |
There was a problem hiding this comment.
Grammar nit in the new comment: "allow that with following switch" reads like a typo. Consider "allow that with the following switch" for clarity.
| // allow that with following switch in their app config file: | |
| // allow that with the following switch in their app config file: |
Summary
Fixes a rendering gap where
RenderTargetBitmapcould produce blank output when no display devices are attached.What changed
canRenderWithoutDisplayDevicesto compose pipeline signatures.CComposition::ProcessCompositionto allow rendering when this flag is set.RenderTargetBitmap-style rendering.falsethere (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