Enhancement of RenderTargetBitmap to Support Hardware Rendering
- Dominant language
- C#
- Stars
- 7.7k
- Forks
- 1.3k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 61
Description
# Description
In WPF, `RenderTargetBitmap` (also RTB) currently only supports software rendering. This limitation leads to performance bottlenecks and causes `ShaderEffect` implementations to become ineffective. Enhancing RTB to support hardware rendering would provide significant performance improvements and enable high-quality rendering features that are currently restricted. This limitation has been extensively discussed in the past (#144, [Add optional hardware acceleration to RenderTargetBitmap](https://stackoverflow.com/questions/4565828/add-optional-hardware-acceleration-to-rendertargetbitmap) and some website was lost: [RenderTargetBitmap and Hardware WPF Rendering](https://social.msdn.microsoft.com/Forums/office/en-US/9c5f579e-7c3a-48f8-981f-7fb3517eca6a/rendertargetbitmap-and-hardware-wpf-rendering)).
As a developer who is proficient in graphics and C#, one of my requirements is to export WPF-rendered UI as video efficiently. Current methods such as using `BitmapCache` (which cannot retrieve content back to memory) and hooking DirectX APIs (which is complex and unstable) are not feasible solutions.
# Technical Investigation
Upon inspecting the WPF source code in `api_factory.cpp`, I found that the creation of `RenderTargetBitmap` is restricted to software rendering:
```cpp
STDMETHODIMP
CMILFactory::CreateBitmapRenderTarget(
UINT width,
UINT height,
MilPixelFormat::Enum format,
FLOAT dpiX,
FLOAT dpiY,
MilRTInitialization::Flags dwFlags,
__deref_out_ecount(1) IMILRenderTargetBitmap **ppIRenderTargetBitmap
)
{
// ...
if (SUCCEEDED(hr))
{
if ( !(dwFlags & MilRTInitialization::HardwareOnly) )
{
MIL_THR(CSwRenderTargetBitmap::Create(
width,
height,
format,
dpiX,
dpiY,
DisplayId::None,
ppIRenderTargetBitmap
DBG_STEP_RENDERING_COMMA_PARAM(NULL) // pDisplayRTParent
));
}
else
{
MIL_THR(WGXERR_NOTIMPLEMENTED);
}
}
// ...
}
```
# Proposed Modification for Hardware Rendering
To enable hardware rendering, I modified the above code as follows:
```cpp
if (SUCCEEDED(hr))
{
HWND const hwnd = GetDesktopWindow(); // TODO: get D3D Device is better
CDisplaySet const *pDisplaySet = NULL;
MIL_THR(GetCurrentDisplaySet(&pDisplaySet));
CDisplay const *pDisplay = pDisplaySet->Display(0); // TODO: multi-display?
CHwDisplayRenderTarget *pRenderTarget = NULL;
MIL_THR(CHwDisplayRenderTarget::Create(
hwnd,
MilWindowLayerType::NotLayered,
pDisplay,
D3DDEVTYPE_HAL,
dwFlags,
OUT &pRenderTarget));
IntermediateRTUsage rtUsage;
rtUsage.flags = IntermediateRTUsage::ForBlending;
rtUsage.wrapMode = MilBitmapWrapMode::Extend;
MIL_THR(pRenderTarget->CreateRenderTargetBitmap(
width,
height,
rtUsage,
dwFlags,
ppIRenderTargetBitmap));
}
```
# Results and Observations
After compiling `wpfgfx_cor3.dll` with the modifications, WPF operates normally and, for the first time, provides high-performance rendering with support for `ShaderEffect`. I successfully converted the output to a `WriteableBitmap` and encoded it as a JPEG image. I am excited to share this successful update and would like to submit a PR to address this issue.
# Concerns and Considerations
One potential reason why this approach might not have been implemented officially could be due to HwRenderTarget requiring a context (D3DDevice) binding. Since `RenderTargetBitmap` was developed later, it doesn't fit into DUCE and requires separate API calls, where the device context isn't readily available.
# Proposed Solution
I plan to implement a new class derived from `CHwSurfaceRenderTarget`. This class will attempt to access the associated hardware `m_pD3DDevice` at creation (as WPF consistently uses a single D3DDevice). If unavailable, it defaults to `CD3DDeviceManager::GetSWDevice`. The new class's `CreateRenderTargetBitmap` will handle the selection of the correct RTB automatically. However, it raises key issues such as how to consistently access WPF's unique `m_pD3DDevice` and handle device loss (e.g., due to graphics driver updates).
I look forward to your feedback on this proposal.
Contributor guide
Assessment
This issue has not been assessed yet.