我试图了解 Office 2013 如何将内容绘制到屏幕上。到目前为止我的发现:
CreateWicBitmapRenderTarget
创建基于 Wic 的位图。此时我很困惑 Office 如何继续。所以我的问题是:
将基于 Wic 的渲染目标复制到屏幕有哪些可能的方法?
我非常确定,Office 最终会使用交换链(可能在 Windows 7 上用
CreateSwapChain
和 Windows 8 上的 CreateSwapChainForHwnd
创建)。我正在逐步执行各种“可疑”函数,例如 CreateBitmapFromWicBitmap
和 CreateBitmapFromDxgiSurface
) - 但我不明白 API 调用的完整链。
编辑(对 MooseBoys 的回答): 这不是在屏幕上放置像素的一般问题。像素已经位于一个 RenderTarget(使用 CreateWicBitmapRenderTarget 创建的渲染目标,然后使用 BeginDraw/DrawGlyphRun/EndDraw 绘制)上,现在我想将这些像素移动到另一个 RenderTarget(实际屏幕上的渲染目标)。 在 GDC 世界中,我会寻找类似 BitBlt 的工具,将像素从一个 HDC 移动到另一个 HDC。我想知道 D2D 世界中的协议是什么。
很多年后这个问题仍然没有答案,所以这里是:
在 OP 给出的 MS Office 示例中,使用 WIC 渲染目标和支持位图主要是因为 WIC 不具有 Direct2D 的强线程关联性。 WIC 目标和位图可以在一个线程中创建和调整大小,并使用后台线程中的新数据进行更新(例如,在池任务或长时间运行的任务中)。相反,Direct2D 目标和位图必须在同一线程中创建、绘制和渲染。
虽然可以在后台线程中创建和使用 D2D 位图,但线程关联意味着必须将后台 D2D 位图复制到某种其他类型的位图(例如 WIC 位图)中,然后才能从另一个线程访问它。要渲染它以供显示,需要将其复制两次:一次是为了能够从 UI 线程读取它,第二次是将其转换回属于 UI 上下文的另一个 D2D 位图。背景 D2D 位图很少值得这么麻烦。
WIC 位图允许跨线程(跨上下文)访问,使它们更加灵活。但是,WIC 位图无法直接渲染到屏幕设备上下文进行显示。 要显示 WIC 位图,您必须输入 UI 上下文并将 WIC 位图复制到 D2D 位图,然后您可以将其绘制到 UI 上下文目标,使其准备好呈现在设备屏幕上进行显示。
这里是一些从使用 c#、SharpDx 和 Dx11.1 的快速滚动通道显示中摘录和浓缩的示例代码。设备管理器、交换链和其他元素在其他地方定义,但概念应该很清晰。
// Must be executed in the UI context
private void DrawWicBitmapToDisplayContext(SharpDX.WIC.Bitmap wicBitmap)
{
var context2D = deviceManager.Direct2DContext; // previously created
context2D.Transform = Matrix3x2.Identity;
// if you have multiple alternate targets for context2D overlays, select the desired one here
// Convert from Wic Bitmap to a d2d bitmap before drawing to the DXGI surface target
using(TraceBitmap_D2D1_bmp1 = SharpDX.Direct2D1.Bitmap1.FromWicBitmap(context2D, wicBitmap, traceBitmapProperties), "TraceBitmap"))
{
context2D.BeginDraw();
context2D.DrawBitmap(TraceBitmap_D2D1_bmp1, 1.0f, SharpDX.Direct2D1.InterpolationMode.HighQualityCubic);
context2D.EndDraw();
}
}
以下是使其在设备屏幕上可见的示例代码:
// Must be executed in the UI context
public void PresentToScreen()
{
var device3D = deviceManager.Direct3DDevice;
var context3D = deviceManager.Direct3DContext;
var bgColorSharpDx = SharpDX.Color.Transparent; // or as desired
// Set up the context for rendering.
// RectangleVertexBuffer contains two triangles making up a rectangle that matches the display area.
device3D.ImmediateContext.InputAssembler.SetVertexBuffers(0, rectangleVertexBufferBinding);
device3D.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
device3D.ImmediateContext.OutputMerger.SetRenderTargets(renderTargetView);
device3D.ImmediateContext.ClearRenderTargetView(renderTargetView, bgColorSharpDx);
using(var newestWicBitmap = GetNewestWicBitmapFromPool()) // double-buffering method not shown
{
DrawWicBitmapToDisplayContext(newestWicBitmap); // code is shown above
}
bool vSync = false; // don't use vSync in windowed modes (deadlocks on resize)
swapChain.Present(vSync ? 1 : 0, PresentFlags.None, new PresentParameters()); // requires DX11.1
}
大概扩展方法 DeviceContext.DrawWicBitmap() 可以接受 WIC 位图并以不可见的方式处理转换。