Каковы наилучшие методы многопоточности с Direct2D и DXGI (взаимодействие D3D)?

В идеале я хотел бы иметь несколько рабочих потоков, чтобы иметь возможность отображать цели рендеринга за пределами экрана, а затем «переносить» отображаемый контент в цель на экране. С целями рендеринга hwnd это не кажется проблемой (у msdn есть пример).

Я не совсем уверен, как это сделать, когда цель рендеринга на экране основана на цепочке обмена DXGI. Насколько я знаю, у меня может быть только одна цепочка подкачки на окно. Поэтому у меня может быть только одна цель рендеринга на основе цепочки обмена. Это означает, что рендеринг на экране может быть выполнен только через эту единственную цель рендеринга.

Если мои приведенные выше предположения верны, как лучше всего справиться с многопоточным рендерингом? Нужно ли сериализовать доступ к цели на экране? Должны ли рабочие потоки совместно использовать одну многопоточную фабрику d2d? Может ли экранная цель BeginDraw/EndDraw/Present выполняться в рабочих потоках (т. е. потоках, которые не создавали экранную цель), если имеется надлежащий механизм блокировки?

Буду признателен за любые предложения. Спасибо.


person Dan    schedule 05.06.2011    source источник


Ответы (2)


Я сейчас решаю эту же проблему! Согласно моему чтению в MSDN, лучший способ:

  • Используйте многопоточную фабрику — это позволяет вам делиться ресурсами (см. также ссылку с цитатой ниже).
  • Будьте осторожны с некоторыми тупиковыми ситуациями (подробности ниже).
  • Вероятно, вам нужно использовать ID2D1MultiThread для блокировки при рисовании с использованием Direct3D.

У меня еще нет надежно работающего многопоточного набора функций Direct2D, даже после этого, так что это все, что я знаю до сих пор - я еще не знаю о других предостережениях и т. Д., Которые наверняка существуют.

Некоторые полезные ключевые моменты:

Вы можете создать многопоточный экземпляр фабрики Direct2D. Вы можете использовать и совместно использовать многопоточную фабрику и все ее ресурсы из более чем одного потока, но доступ к этим ресурсам (через вызовы Direct2D) сериализуется Direct2D, поэтому конфликтов доступа не возникает. Если ваше приложение вызывает только API-интерфейсы Direct2D, такая защита автоматически обеспечивается Direct2D на детальном уровне с минимальными затратами.

ID2D1Factory* m_D2DFactory;

// Create a Direct2D factory.
HRESULT hr = D2D1CreateFactory(
    D2D1_FACTORY_TYPE_MULTI_THREADED,
    &m_D2DFactory
);

Также есть очень важное предупреждение:

Многопоточность

Когда вы используете DXGI в приложении с несколькими потоками, вам нужно быть осторожным, чтобы избежать взаимоблокировки, когда два разных потока ожидают завершения друг друга. Есть две ситуации, когда это может произойти.

  • Поток рендеринга не является потоком перекачки сообщений.
  • Поток, выполняющий DXGI API, не является тем же потоком, который создал окно.

Будьте осторожны, чтобы поток обработки сообщений никогда не ждал потока рендеринга при использовании полноэкранных цепочек обмена. Например, вызов IDXGISwapChain1::Present1 (из потока рендеринга) может привести к тому, что поток рендеринга будет ожидать в потоке передачи сообщений. Когда происходит изменение режима, этот сценарий возможен, если Present1 вызывает ::SetWindowPos() или ::SetWindowStyle() и любой из этих методов вызывает ::SendMessage(). В этом сценарии, если поток сообщений имеет охраняющий критический раздел или если поток рендеринга заблокирован, два потока заблокируются.

person David    schedule 24.01.2014

Для внеэкранных целей рендеринга вы можете создать отдельные D2DFactory и присоединить их к соответствующим внеэкранным целям рендеринга, созданным с помощью CreateWicBitmapRenderTarget или CreateDxgiSurfaceRenderTarget. При передаче его на экранную цель вам придется дождаться завершения всех потоков, а затем передавать каждый внеэкранный RT на экранный RT один за другим.

person Ramya Maithreyi    schedule 14.06.2011