高效的Direct2D多线程 [英] Efficient Direct2D multithreading

查看:392
本文介绍了高效的Direct2D多线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Windows应用商店编写一个电子书阅读器应用程序.我正在使用Direct2D + DXGI交换链在屏幕上呈现书籍页面.

I'm writing a ebook reader app for Windows Store. I'm using Direct2D + DXGI swap chains to render book pages on screen.

我的书内容有时非常复杂(几何,位图,蒙版等),因此呈现它可能需要100毫秒的时间.因此,我尝试在单独的线程中对位图进行屏幕外渲染,然后仅在主线程中显示此位图.

My book content sometimes is quite complex (geometry, bitmaps, masks, etc), so it can take up to 100 ms to render it. So I'm trying to do an off-screen rendering to a bitmap in a separate thread, and then just show this bitmap in main thread.

但是,我不知道如何有效地做到这一点.

However, I can't figure how to do it efficiently.

到目前为止,我已经尝试了两种方法:

So far I've tried two approaches:

  1. 使用带有D2D1_FACTORY_TYPE_MULTI_THREADED标志的单个ID2D1Factory,创建ID2D1BitmapRenderTarget并在后台线程中使用它进行屏幕外渲染. (这另外需要IDXGISwapChain::Present操作上的ID2D1Multithread::Enter/Leave).问题是,后台线程中的ID2D1RenderTarget::EndDraw操作有时需要长达100ms的时间,并且由于内部Direct2D锁定,在此期间主线程渲染被阻止.

  1. Use a single ID2D1Factory with D2D1_FACTORY_TYPE_MULTI_THREADED flag, create ID2D1BitmapRenderTarget and use it in background thread for off-screen rendering. (This additionally requires ID2D1Multithread::Enter/Leave on IDXGISwapChain::Present operations). Problem is, ID2D1RenderTarget::EndDraw operation in background thread sometimes take up to 100ms, and main thread rendering is blocked for this period due to internal Direct2D locking.

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

Use a separate ID2D1Factory in background thread (as described in http://www.sdknews.com/ios/using-direct2d-for-server-side-rendering) and turn off internal Direct2D synchronization. There is no cross-locking betwen two threads in this case. Unfortunately, in this case I can't use resulting bitmap in main ID2D1Factory directly, because it belongs to a different factory. I have to move bitmap data to CPU memory, then copy it into GPU memory of the main ID2D1Factory. This operation also introduce significant lags (I believe it to be due to large memory accesses, but I'm not sure).

有没有办法有效地做到这一点?

Is there a way to do this efficiently?

P.S.此处列出了Acer Switch 10平板电脑的所有时间.在常规的Core i7 PC上,两种方法都可以正常工作,而不会出现明显的延迟.

P.S. All the timing here are given for Acer Switch 10 tablet. On regular Core i7 PC both approaches work without any visible lag.

推荐答案

好的,我已经找到了解决方案.

Ok, I've found a solution.

基本上,我所需要做的就是修改方法2,以在两个DirectX工厂集之间使用DXGI资源共享.我将跳过所有详细信息(可以在以下位置找到它们: http://xboxforums.create.msdn.com/forums/t/66208.aspx ),但基本步骤是:

Basically, all I needed is to modify approach 2 to use DXGI resource sharing between two DirectX factory sets. I'll skip all the gory details (they can be found here: http://xboxforums.create.msdn.com/forums/t/66208.aspx), but basic steps are:

  1. 创建两组DirectX资源:主要(用于屏幕渲染)和次要(用于屏幕外渲染).
  2. 使用主资源集中的ID3D11Device2,通过CreateTexture2DD3D11_BIND_RENDER_TARGETD3D11_BIND_SHADER_RESOURCED3D11_RESOURCE_MISC_SHARED_NTHANDLED3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX标志创建D3D 2D纹理.
  3. 通过将其转换为IDXGIResource1并使用XGI_SHARED_RESOURCE_READDXGI_SHARED_RESOURCE_WRITE从其调用CreateSharedHandle来从中获取共享句柄.
  4. 通过调用ID3D11Device2::OpenSharedResource1在后台线程中设置的辅助资源中打开此共享纹理.
  5. 获取此纹理(IDXGIKeyedMutex::AcquireSync)的键控互斥锁,从中创建渲染目标(ID2D1Factory2::CreateDxgiSurfaceRenderTarget),在其上绘制并释放互斥锁(IDXGIKeyedMutex::ReleaseSync).
  6. 在主线程上的主资源集中,获取互斥锁并从步骤2中创建的纹理创建共享位图,绘制该位图,然后释放互斥锁.
  1. Create two sets of DirectX resources: main (which will be used to onscreen rendering), and secondary (for offscreen rendering).
  2. Using ID3D11Device2 from main resource set, create D3D 2D texture by CreateTexture2D D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_RESOURCE_MISC_SHARED_NTHANDLE and D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX flags.
  3. Get shared handle from it by casting it to IDXGIResource1 and calling CreateSharedHandle from it with XGI_SHARED_RESOURCE_READ and DXGI_SHARED_RESOURCE_WRITE.
  4. Open this shared texture in secondary resource set in background thread by calling ID3D11Device2::OpenSharedResource1.
  5. Acquire keyed mutex of this texture (IDXGIKeyedMutex::AcquireSync), create render target from it (ID2D1Factory2::CreateDxgiSurfaceRenderTarget), draw on it and release mutex (IDXGIKeyedMutex::ReleaseSync).
  6. On the main thread, in the main resource set, acquire mutex and create shared bitmap from texture created in step 2, draw this bitmap, then release mutex.

请注意,互斥锁必须是必需的.不这样做会导致一些神秘的DirectX调试错误消息,并导致错误的操作甚至崩溃.

Note that mutex locking stuff is necessary. Not doing it results in some cryptic DirectX debug error messages, and erroneous operation or even crashing.

这篇关于高效的Direct2D多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆