Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 高效的Direct2D多线程处理_Multithreading_Direct2d - Fatal编程技术网

Multithreading 高效的Direct2D多线程处理

Multithreading 高效的Direct2D多线程处理,multithreading,direct2d,Multithreading,Direct2d,我正在为Windows应用商店编写电子书阅读器应用程序。我正在使用Direct2D+DXGI交换链在屏幕上呈现书籍页面 我的书内容有时非常复杂(几何体、位图、遮罩等),因此渲染它可能需要100毫秒。所以我尝试在一个单独的线程中对位图进行屏幕外渲染,然后在主线程中显示这个位图 然而,我不知道如何有效地做这件事 到目前为止,我已经尝试了两种方法: 使用带有D2D1工厂类型多线程标志的单个ID2D1Factory,创建ID2D1BitmapRenderTarget并在后台线程中使用它进行屏幕外渲染。(

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

我的书内容有时非常复杂(几何体、位图、遮罩等),因此渲染它可能需要100毫秒。所以我尝试在一个单独的线程中对位图进行屏幕外渲染,然后在主线程中显示这个位图

然而,我不知道如何有效地做这件事

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

  • 使用带有D2D1工厂类型多线程标志的单个
    ID2D1Factory
    ,创建
    ID2D1BitmapRenderTarget
    并在后台线程中使用它进行屏幕外渲染。(这还需要在
    IDXGISwapChain::Present
    操作中执行
    ID2D1Multithread::Enter/Leave
    )。问题是,
    ID2D1RenderTarget::EndDraw
    后台线程中的操作有时需要100毫秒,并且由于内部Direct2D锁定,主线程渲染在此期间被阻止

  • 在后台线程中使用单独的
    ID2D1Factory
    (如中所述),并关闭内部Direct2D同步。在这种情况下,两个线程之间没有交叉锁定。不幸的是,在这种情况下,我不能直接在main
    ID2D1Factory
    中使用生成的位图,因为它属于不同的工厂。我必须将位图数据移动到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资源共享。我将跳过所有血淋淋的细节(它们可以在这里找到:),但基本步骤是:

  • 创建两组DirectX资源:main(用于屏幕上渲染)和secondary(用于屏幕外渲染)
  • 使用主资源集中的
    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
  • 在主线程上,在主资源集中,获取互斥体并从步骤2中创建的纹理创建共享位图,绘制此位图,然后释放互斥体
  • 注意,互斥锁是必要的。不这样做会导致一些隐藏的DirectX调试错误消息,以及错误的操作甚至崩溃