gpt4 book ai didi

multithreading - 如何重做现有的基于Direct2D的库,以一次从多个线程访问功能?

转载 作者:行者123 更新时间:2023-12-04 04:33:25 33 4
gpt4 key购买 nike

我正在使用现有的图形库,其中一种实现使用Direct2D。 (它也可以使用GDI +,Quartz等。)它具有位图对象,笔,画笔等,所有这些都实现为Direct2D对象周围的包装器代码。该库是封闭源代码,很遗憾,我可能无法在此处发布大量内容。

我发现使用多个线程时-一个线程生产者,创建位图并绘制到它们,一个线程消费者,在屏幕上绘制它们-有时生产者线程产生的位图是完全空白的:图像数据(内部纹理)全为零。 (位图是纹理周围的包装对象,但可能代表一个位图,您可能会想到GDI +位图对象。我确定您熟悉一般的范例。)请注意,它永远不会崩溃,只是有时默默地失败。一个典型的症状是绘制位图数据,调用Unmap从缓冲区复制回纹理,并在以后尝试绘制它时发现纹理为空白。

我认为正在发生的是:

  • 要像我的生产者线程一样直接写入像素数据,该库提供了MapUnmap函数来直接访问像素数据。有一个DirectX10设备,一个“共享设备”,它用于调用CopyResource从内部纹理复制到缓冲区,然后可以将其自由写入,然后以另一种方式取消映射副本的映射。我认为有时这会无声地失败。
  • 这种共享设备的方法在整个库中都使用:有一个共享的渲染目标(ID2D1RenderTarget)用于创建共享的位图(ID2D1Bitmap)等。该方法似乎是图形/位图对象当然具有自己的纹理,但是对它们的所有操作都是通过一台设备,一个渲染目标等完成的。
  • 当多个线程同时使用“位图”时,多个操作可能会失败:CopyResource(如上所述),它返回void而不是HRESULT,有时似乎失败; ID2D1RenderTarget::DrawBitmap 也静默失败。

  • 因此,我想解决这个问题,并且 侵入库足够的线程安全性,因此我可以可靠地实现生产者-消费者线程系统。 我该怎么做?

    我一直在大量阅读有关从多个线程使用Direct2D的正确方法的文章。
  • 已经使用 D2D1_FACTORY_TYPE_MULTI_THREADED flag创建了所有工厂。
  • 我尝试将 ID2D1MultiThread interface用于synchronization via the factories。但是,这似乎仅在Windows 7及更高版本上可用:我需要使用DirectX10级的Vista + API。
  • 我也尝试过使用ID3D10Multithread interface进行同步。我遇到了一些问题:

    我不确定应该在哪里同步,或者在什么同步。如果它是细粒度的(例如在MapUnmap调用周围,或者在MSDN指示所需的Present附近),则同步无效:上述方法调用仍然失败。如果是粗粒度的,则在调用ID2D1RenderTarget::BeginDraw时输入锁,将其保留在所有图形中,然后在调用ID2D1RenderTarget::EndDrawID2D1RenderTarget::Flush和/或IDXGISwapChain::Present后留下锁,这似乎工作得很不错……直到几秒钟后我才输入僵局。 MSDN对此进行了描述,

    Be careful that you never have the message-pump thread wait on the render thread when you use full-screen swap chains. For instance, calling IDXGISwapChain1::Present1 (from the render thread) may cause the render thread to wait on the message-pump thread. When a mode change occurs, this scenario is possible if Present1 calls ::SetWindowPos() or ::SetWindowStyle() and either of these methods call ::SendMessage(). In this scenario, if the message-pump thread has a critical section guarding it or if the render thread is blocked, then the two threads will deadlock. - Source



    ...但是没有如何避免的指导。我的死锁似乎是由于两个线程都试图同时访问图形而引起的,例如,同时调用BeginDraw。似乎有第二个锁在起作用,因为如果只有一个锁,那么就不会有死锁。
  • 我尝试过保留“共享”设备,渲染目标等的每个线程实例。也就是说,每个对象的每种类型的每个线程都有一个实例,然后该线程中运行的所有代码都将使用该实例。除纹理外,此方法效果很好:似乎(通过另一个设备)访问在另一个线程上下文中创建的纹理根本不起作用。在对该技术进行编码时,经常会遇到方法失败的问题-最常见的是CreateSharedBitmap,而失败的是D2DERR_UNSUPPORTED_OPERATION,其中纹理来自另一个线程(因此,另一个设备)。这是关键位,因为位图对象在一个线程中创建的(包装纹理)需要能够在另一个线程中绘制。根据编码方式的不同,线程与设备,渲染目标等之间可能有1:1的关系,也可能没有。

    如果我可以解决此,我认为我编写的其余代码对我来说足够好用,可以实现我所需要的。有可能-以及如何? -在ID3D10Texture2D之间交叉ID3D10Device1?是否有必要在线程之间使用单独的设备?

  • 总的来说,我有些困惑, 正在寻求熟悉Direct3D 10和Direct2D的人有关最佳方法的建议。我认为有两种可行的可能性:
  • 找出ID3D10Multithread interface锁定。 Google上没有太多东西,也没有关于避免MSDN上的死锁的建议。
  • 继续使用每个线程都有其自己的设备,共享的渲染目标等的机制。(这有多少必要?例如,每个线程可能只有一个设备,而每个渲染目标又有可能吗?) ,纹理资源如何从一个线程到另一个线程,这意味着从一个设备到另一个设备?基本上,使用在一个线程内部创建的纹理的包装位图对象需要可用于绘制第二个线程。

  • 但也很想听听其他可能性。我们将非常感谢您听到有关正确的Direct2D线程实现的任何建议。

    最佳答案

    适用于我的模型是单个D2D和D3D工厂以及每个线程的D2D渲染目标。同步是通过我自己的关键部分完成的。
    我不需要在线程之间共享位图。

    在您的情况下应该起作用的是,每个线程都具有单独的所有内容(工厂,渲染目标等),并使用共享资源。这也回答了您关于如何在ID3D10Texture2D之间交叉ID3D10Device1的问题。您将需要以下功能:
    IDXGIResource::GetSharedHandle
    ID3D10Device::OpenSharedResource
    IDXGIKeyedMutex::AcquireSync

    或每个流程仅创建一个工厂,一个渲染目标等,并通过您自己的关键部分进行同步。
    在这种情况下,需要围绕每个接触使用另一个线程的位图的批处理(BeginDraw-EndDraw)的每个D2D或D3D调用进行同步。

    我发现在处理多线程问题时,同时启用D2D和D3D调试层并使用Windows 8.1 SDK很有帮助。新的Windows 8.1 SDK包含有关多线程问题的新消息。您无需在Windows 8.1上即可使用8.1 SDK。

    关于multithreading - 如何重做现有的基于Direct2D的库,以一次从多个线程访问功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21344988/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com