David
David

Reputation: 13580

How do I rework an existing Direct2D-based library to function accessed from multiple threads at once?

I am using an existing graphics library, one implementation of which uses Direct2D. (It can also use GDI+, Quartz, etc.) It has bitmap objects, pens, brushes etc, all implemented as wrapper code around Direct2D objects. The library is closed source and unfortunately I probably can't post extensive portions of it here.

I have found that when using multiple threads - one thread producer, creating bitmaps and drawing to them, one thread consumer, drawing them onscreen - sometimes the bitmap the producer thread produces is completely blank: the image data (internally a texture) is all zeroes. (A bitmap is a wrapper object around a texture, but representing a bitmap like a you might think of a GDI+ bitmap object, perhaps. I'm sure you're familiar with the general paradigm.) Note that it never crashes, just sometimes silently fails. A typical symptom will be drawing to the bitmap data, calling Unmap to copy from the buffer back to the texture, and finding when you later try to draw it that the texture is blank.

What I think is happening is:

So, I would like to solve the problem and hack into the library enough thread safety I can achieve my producer-consumer thread system reliably. How do I do this?

I've been doing a lot of reading about the right way to use Direct2D from multiple threads.

All up I'm a bit stumped and am seeking advice from those familiar with Direct3D 10 and Direct2D about the best approach. I think there are two viable possibilities:

  1. Figure out the ID3D10Multithread interface locking. There isn't much on Google, nor much advice about avoiding deadlocks on MSDN.

  2. Continue with the mechanism where every thread has its own device, shared render target, etc. (How much of this is necessary - is it possible, say, for there to be one device only but individual render targets per thread?) If so, how can texture resources cross from one thread to another, where that may mean from one device to another? Basically, a wrapper bitmap object which uses a texture internally created in one thread needs to be useable to draw on a second.

but am keen to hear about any other possibilities too. Any advice whatsoever about correct Direct2D threading implementations will be very gratefully heard.

Upvotes: 4

Views: 1370

Answers (1)

vt.
vt.

Reputation: 1375

The model that works for me is single D2D and D3D factory and per-thread D2D render targets. Synchronization is done via my own critical sections. I don't need to share bitmaps between threads though.

What should work in your case is either having separate everything (factory, render targets, etc.) per every thread and work with shared resources. This also answers your question on how to cross ID3D10Texture2Ds between ID3D10Device1s. You'll need those functions: IDXGIResource::GetSharedHandle ID3D10Device::OpenSharedResource IDXGIKeyedMutex::AcquireSync

Or create just one factory, one render target, etc. per process and sync via your own critical sections. In this case, synchronization needs to be done around every D2D or D3D call that touches a batch (BeginDraw-EndDraw) which uses another thread's bitmaps.

I found enabling both D2D and D3D debug layers and using Windows 8.1 SDK very helpful while working on multi-threading issues. New Windows 8.1 SDK has new messages for multi-threading issues. You don't need to be on Windows 8.1 to use 8.1 SDK.

Upvotes: 3

Related Questions