高效的Direct2D多线程技术

8
我正在为Windows Store编写一款电子书阅读器应用程序。我使用Direct2D + DXGI交换链来在屏幕上呈现书页。
我的书籍内容有时相当复杂(几何、位图、掩模等),因此渲染可能需要高达100毫秒的时间。因此,我正在尝试在单独的线程中进行离屏渲染到位图,然后在主线程中仅显示该位图。
但是,我无法有效地解决这个问题。
到目前为止,我已经尝试了两种方法:
  1. 使用带有 D2D1_FACTORY_TYPE_MULTI_THREADED 标志的单个 ID2D1Factory,在后台线程中创建 ID2D1BitmapRenderTarget 并用于离屏渲染(这还需要在 IDXGISwapChain::Present 操作上使用 ID2D1Multithread::Enter/Leave)。问题是,后台线程中的 ID2D1RenderTarget::EndDraw 操作有时需要长达 100 毫秒,由于内部 Direct2D 锁定,主线程渲染会被阻塞。

  2. 在后台线程中使用单独的 ID2D1Factory(如 http://www.sdknews.com/ios/using-direct2d-for-server-side-rendering 中所述),并关闭内部 Direct2D 同步。在这种情况下,两个线程之间没有交叉锁定。不幸的是,在这种情况下,我不能直接在主 ID2D1Factory 中使用生成的位图,因为它属于不同的工厂。我必须将位图数据移动到 CPU 内存,然后将其复制到主 ID2D1Factory 的 GPU 内存中。此操作也会引入显著的延迟(我认为这是由于大量的内存访问,但我不确定)。

有没有一种高效的方法来完成这个任务?

P.S. 这里的所有时间都是针对 Acer Switch 10 平板电脑的。在普通的 Core i7 PC 上,这两种方法都可以无延迟地工作。

2个回答

9

好的,我找到了一个解决方案。

基本上,我只需要修改第二种方法,使用两个DirectX工厂集之间的DXGI资源共享即可。我会跳过所有令人生畏的细节(可以在此处找到: http://xboxforums.create.msdn.com/forums/t/66208.aspx),但基本步骤如下:

  1. 创建两组DirectX资源: 主要的(用于屏幕渲染)和次要的(用于离屏渲染)。
  2. 使用主资源集中的ID3D11Device2,通过CreateTexture2D D3D11_BIND_RENDER_TARGETD3D11_BIND_SHADER_RESOURCED3D11_RESOURCE_MISC_SHARED_NTHANDLED3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX标志创建D3D 2D纹理。
  3. 通过将其转换为IDXGIResource1并调用CreateSharedHandle来从中获取共享句柄,具有XGI_SHARED_RESOURCE_READDXGI_SHARED_RESOURCE_WRITE
  4. 通过调用ID3D11Device2::OpenSharedResource1在后台线程中打开此共享纹理中的次要资源集。
  5. 获取此纹理的键控互斥量(IDXGIKeyedMutex::AcquireSync),从中创建渲染目标(ID2D1Factory2::CreateDxgiSurfaceRenderTarget),在其上绘制并释放互斥量(IDXGIKeyedMutex::ReleaseSync)。
  6. 在主线程中,在主资源集中获取互斥量并从第2步中创建的纹理中创建共享位图,绘制此位图,然后释放互斥量。

请注意,互斥锁定必需。不这样做会导致一些难以理解的DirectX调试错误消息,并出现错误操作或甚至崩溃。


2
tl;dr: 在软件模式下,在后台线程中渲染为位图。在硬件模式下,从位图绘制到呈现目标并在UI线程上绘制。
迄今为止我找到的最好方法是使用后台线程进行软件渲染(IWICImagingFactory :: CreateBitmap和ID2D1Factory :: CreateWicBitmapRenderTarget),然后通过ID2D1RenderTarget :: CreateBitmapFromWicBitmap将其复制回具有硬件呈现目标的线程上的硬件位图。然后使用ID2D1RenderTarget :: DrawBitmap进行blit。
这就是paint.net 4.0进行选择渲染的方式。当您使用套索工具绘制选择时,它将使用后台线程异步绘制选择轮廓(UI线程不等待此操作完成)。由于笔画样式和动画,您可能会得到非常复杂的多边形。我将其渲染4次,其中每个动画帧对虚线笔画样式具有稍微不同的偏移量。
显然,随着多边形变得更加复杂(也就是说,如果您一直涂鸦),这种渲染可能需要一些时间。当您使用Move Selection工具进行变换(旋转,平移,缩放)时,我还有一些其他特殊优化:如果后台线程尚未使用新变换重新渲染当前多边形,则我将使用应用新变换的旧位图(具有当前多边形和旧变换)。当后台线程赶上时,选择轮廓可能会失真(缩放)或剪裁(平移到不可视区域之外),但这是为了60fps的响应而支付的小代价。这种优化非常有效,因为您不能同时修改选择的多边形和变换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接