如何在屏幕上发送基于Wic的渲染目标?

问题描述 投票:0回答:1

我试图了解 Office 2013 如何将内容绘制到屏幕上。到目前为止我的发现:

  1. Office 正在使用
    CreateWicBitmapRenderTarget
    创建基于 Wic 的位图。
  2. 使用此渲染目标,Office 使用各种绘图方法。它按预期使用 BeginDraw/EndDraw 包装这些调用。
  3. Office 使用 DrawGlyphRun 方法在 Wic 位图上绘制文档的文本(即 DrawGlyphRun 的 This 指针是从 CreateWicBitmapRenderTarget 返回的指针)。

此时我很困惑 Office 如何继续。所以我的问题是:

将基于 Wic 的渲染目标复制到屏幕有哪些可能的方法?

我非常确定,Office 最终会使用交换链(可能在 Windows 7 上用

CreateSwapChain
和 Windows 8 上的
CreateSwapChainForHwnd
创建)。我正在逐步执行各种“可疑”函数,例如
CreateBitmapFromWicBitmap
CreateBitmapFromDxgiSurface
) - 但我不明白 API 调用的完整链。

编辑(对 MooseBoys 的回答): 这不是在屏幕上放置像素的一般问题。像素已经位于一个 RenderTarget(使用 CreateWicBitmapRenderTarget 创建的渲染目标,然后使用 BeginDraw/DrawGlyphRun/EndDraw 绘制)上,现在我想将这些像素移动到另一个 RenderTarget(实际屏幕上的渲染目标)。 在 GDC 世界中,我会寻找类似 BitBlt 的工具,将像素从一个 HDC 移动到另一个 HDC。我想知道 D2D 世界中的协议是什么。

ms-office reverse-engineering direct3d direct2d
1个回答
0
投票

很多年后这个问题仍然没有答案,所以这里是:

在 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 位图并以不可见的方式处理转换。

© www.soinside.com 2019 - 2024. All rights reserved.