Multithreading 高效的Direct2D多线程处理
我正在为Windows应用商店编写电子书阅读器应用程序。我正在使用Direct2D+DXGI交换链在屏幕上呈现书籍页面 我的书内容有时非常复杂(几何体、位图、遮罩等),因此渲染它可能需要100毫秒。所以我尝试在一个单独的线程中对位图进行屏幕外渲染,然后在主线程中显示这个位图 然而,我不知道如何有效地做这件事 到目前为止,我已经尝试了两种方法:Multithreading 高效的Direct2D多线程处理,multithreading,direct2d,Multithreading,Direct2d,我正在为Windows应用商店编写电子书阅读器应用程序。我正在使用Direct2D+DXGI交换链在屏幕上呈现书籍页面 我的书内容有时非常复杂(几何体、位图、遮罩等),因此渲染它可能需要100毫秒。所以我尝试在一个单独的线程中对位图进行屏幕外渲染,然后在主线程中显示这个位图 然而,我不知道如何有效地做这件事 到目前为止,我已经尝试了两种方法: 使用带有D2D1工厂类型多线程标志的单个ID2D1Factory,创建ID2D1BitmapRenderTarget并在后台线程中使用它进行屏幕外渲染。(
ID2D1Factory
,创建ID2D1BitmapRenderTarget
并在后台线程中使用它进行屏幕外渲染。(这还需要在IDXGISwapChain::Present
操作中执行ID2D1Multithread::Enter/Leave
)。问题是,ID2D1RenderTarget::EndDraw
后台线程中的操作有时需要100毫秒,并且由于内部Direct2D锁定,主线程渲染在此期间被阻止ID2D1Factory
(如中所述),并关闭内部Direct2D同步。在这种情况下,两个线程之间没有交叉锁定。不幸的是,在这种情况下,我不能直接在mainID2D1Factory
中使用生成的位图,因为它属于不同的工厂。我必须将位图数据移动到CPU内存中,然后将其复制到主ID2D1Factory
的GPU内存中。这个操作还引入了显著的延迟(我认为这是由于大内存访问,但我不确定)另外,这里给出的所有时间都是针对Acer Switch 10平板电脑。在常规的Core i7 PC上,这两种方法都可以在没有任何明显滞后的情况下工作。tl;dr:在软件模式下在后台线程上渲染位图。从位图绘制以在硬件模式下在UI线程上渲染目标 到目前为止,我能找到的最好的方法是在软件渲染中使用后台线程(
iwicmagingfactory::CreateBitmap
和ID2D1Factory::CreateWicBitmapRenderTarget
)然后通过ID2D1RenderTarget::CreateBitmapFromWicBitmap
将其复制回具有硬件渲染目标的线程上的硬件位图。然后使用ID2D1RenderTarget::DrawBitmap
将其禁用
这就是paint.net 4.0进行选择渲染的方式。当您使用lasso工具绘制选择时,它将使用背景线程异步绘制选择轮廓(UI线程不会等待完成)。由于笔划样式和动画,最终可能会生成非常复杂的多边形。我渲染了4次,其中每个动画帧的虚线笔划样式的偏移略有不同
显然,随着多边形变得更加复杂,这种渲染可能需要一段时间(也就是说,如果您继续涂鸦一段时间)。当您使用移动选择工具进行变换(旋转、平移、缩放)时,我还有一些其他特殊优化:如果背景线程尚未使用新变换重新渲染当前多边形,则我将渲染旧位图(使用当前多边形和旧变换)应用新变换后。当背景线程赶上时,选择的轮廓可能会被扭曲(缩放)或剪裁(在可视区域外平移),但为60fps的响应速度付出的代价很小。这种优化效果非常好,因为您不能同时修改多边形和选择的变换。好的,我找到了解决方案 基本上,我所需要的只是修改方法2,以便在两个DirectX工厂集之间使用DXGI资源共享。我将跳过所有血淋淋的细节(它们可以在这里找到:),但基本步骤是:
ID3D11Device2
,通过CreateTexture2D
D3D11_BIND_RENDER_TARGET
,D3D11_BIND_SHADER_resource
,D3D11_resource_MISC_SHARED_NTHANDLE
和D3D11_resource_MISC_SHARED_keydmutex
标志创建D3D11二维纹理IDXGIResource1
并使用XGI\u shared\u RESOURCE\u READ
和DXGI\u shared\u RESOURCE\u WRITE从中调用CreateSharedHandle
来获取共享句柄
ID3D11Device2::OpenSharedResource1
在后台线程的辅助资源集中打开此共享纹理IDXGIKeyedMutex::AcquireSync
),从中创建渲染目标(ID2D1Factory2::CreateDxgiSurfaceRenderTarget
),在其上绘制并释放互斥体(IDXGIKeyedMutex::ReleaseSync
)