2

I'm trying to create a simple D2D game engine (it must be able to display and move images in a window, at least), and everything went right until the moment when I decided to switch to the multithreaded version. I read this MSDN article, and it recommends using one multithreaded factory from several threads. But this article claims it would be more effective to have several single-threaded factories (though the article describes server-side rendering scenario, the principle is the same for my case, am I wrong?). When I tried to use one-thread-one-factory approach, all the images are displayed and moved, but there's terrible flickering. In my WM_PAINT handler I'm trying to do something like this:

for (CSingleThreadEngine *pElSingleThreadEngine : m_SingleThreadEngines) //each CSingleThreadEngine instance has its own D2D factory and an image collection
    pElSingleThreadEngine->Draw();

and pElSingleThreadEngine->Draw() does drawing like this:

m_pRenderTarget->BeginDraw();
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
for (CGameImage *pImage : m_GameImages)
{
    if (FAILED(pImage->Draw()))
        throw runtime_error("An object cannot be drawn");
}
m_pRenderTarget->EndDraw();

I think the wrong thing here is having several ID2D1HwndRenderTarget instances for just one window because if I make drawing each thread in a separate window, it works just fine. But I want to draw in one window only, and I can't avoid using multiple ID2D1HwndRenderTarget instances for this purpose. So my questions are:

  1. What are the best practices for creating multithreaded Direct2D applications at all?
  2. If the approach I'm using is right, what am I doing wrong and how can I fix it?

Any help would be highly appreciated.

1 Answers1

1

I can't see a reason why you use several HWND render targets for a single window. Have you tried creating off-screen bitmaps for each thread and draw those to a single HWND render target instead?

Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Anton Angelov
  • 1,223
  • 7
  • 19
  • This idea came to me a bit earlier but some objects require to use them only in the thread that created them. So I'm fixing bugs and refactoring the program now. I'll definitely accept your answer if I make it work.:) – GreenForester May 12 '14 at 09:50
  • Thanks, it seems the offscreen bitmaps approach really works.) Except that when I'm trying to draw several thousand images I eventually get E_OUTOFMEMORY HRESULT (though there's a lot of free RAM remaining). But the flickering problem has gone away.) – GreenForester May 13 '14 at 15:16
  • There is a difference between the ram, and the video ram. When you create a direct2d bitmap (Id2d1Bitmap), it is loaded in the video ram, until you dispose the interface, and the resource is freed. On the other hand, If you load a image via WIC api, it is stored in the ram. I don't know what is your scenario. – Anton Angelov May 15 '14 at 08:26
  • I currently create WIC bitmap and then use CreateBitmapFromWicBitmap to get ID2D1Bitmap. Strangely enough, if I get E_OUTOFMEMORY and then call CreateBitmapFromWicBitmap again, it succeeds. So I decided to write something like ` while (!m_pD2DBitmap) m_pSingleThreadEngine->m_pRenderTarget->CreateBitmapFromWicBitmap(...);` I'd like to know the exact reason for such behavior though... – GreenForester May 16 '14 at 12:29
  • I don't know what causes your memory to overflow. You can use software like [GPU-Z](http://www.techpowerup.com/gpuz/) to monitor you allocated memory amount, and eventually find out at which point it gets full. Do you expose your bitmaps after you use them? – Anton Angelov May 19 '14 at 12:39
  • I meant to "dispose" your bitmaps instead of "expose". – Anton Angelov May 20 '14 at 07:36
  • I dispose WIC Bitmaps after creating ID2DBitmaps in the following way: `while(!pD2DBitmap) { hResult = m_pSingleThreadEngine->m_pRenderTarget->CreateBitmapFromWicBitmap (m_pFormatConverter, nullptr, &m_pD2DBitmap); } m_pFormatConverter->Release();`. And I dispose ID2DBitmaps when the program exits. GPU-Z shows 160MB memory usage only (1GB total). So I can't understand what's the problem here.:( – GreenForester May 20 '14 at 12:06
  • `m_pFormatConverter` is of type `IWICFormatConverter*` and used instead of `IWICBitmap*`. Raw IWICBitmaps can't be used here because the D2D bitmap doesn't supported all possible pixel and alpha formats, so I have to convert it to the proper format. – GreenForester May 20 '14 at 12:34