Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use the Direct3D Device Manager?

I'd like to share one Direct3D device between multiple threads and objects in my Direct3D application. I came across the Direct3D device manager, which looks like what I want, although I'm not doing any video processing or video acceleration: http://msdn.microsoft.com/en-us/library/windows/desktop/aa965267(v=vs.85).aspx

In my code, I'm doing the following:

  // Create the device manager
  UINT resetToken = 0;
  IDirect3DDeviceManager9* deviceManager = NULL;
  if (FAILED(DXVA2CreateDirect3DDeviceManager9(&resetToken, &deviceManager)))
    return false;

  // Add the device to the device manager
  if (FAILED(deviceManager->ResetDevice(device, resetToken)))
    return false;

  deviceManager->AddRef();

My question is once I've created the Direct3D device manager, how do I share the direct3d device manager with other objects without passing around a pointer to the device manager? Microsoft has specifically said to do the following, but I have no clue what is really meant by the following:

The device owner must provide a way for other objects to get a pointer to the IDirect3DDeviceManager9 interface. The standard mechanism is to implement the IMFGetService interface. The service GUID is MR_VIDEO_ACCELERATION_SERVICE.

Can someone out there show me how to share the device manager by using the IMFGetService interface?

like image 683
Christian Avatar asked Jun 21 '12 21:06

Christian


1 Answers

If you're not doing any video processing, then I see no point in implementing and/or using the IDirect3DDeviceManager9 interface.

Just implement your own way of managing the life-time of the Direct3D device, making the interface pointer available to your objects/threads and to do synchronization. A Direct3D device isn't any kind of magical thing that can only be shared between objects/threads by means of a IDirect3DDeviceManager9. It's just like any other resource. And if you initialize it correctly, you can even call certain methods concurrently from different threads (i.e. pretty much everything that doesn't rely on a device state that might be changed by another thread).

Making the interface pointer available can be as simple as having a singleton that holds the pointer. Or, if your objects/threads already collaborate in some way, they must already have some means of exchanging information. So I suppose you should be able to just extend what you already have to give the objects/threads access to the Direct3D device. And synchronization can be easily done by using a CRITICAL_SECTION.

If you really do want to use IDirect3DDeviceManager9, then - as far as I understand it - you have to implement the IMFGetService interface on all objects from which you want to get access to the IDirect3DDeviceManager9. Implement the GetService function so that when asked for MR_VIDEO_ACCELERATION_SERVICE/IDirect3DDeviceManager9 it returns an interface pointer to the object that manages your Direct3D device.


EDIT: Regarding the code-sample: I hope the explanation given here is enough. Sharing stuff between multiple threads is something that I dare not try to explain with a short code-sample. If you know how to write multi-threaded applications, then using a Direct3D device is not different from how it's done with other resources. And if you don't know how to write multi-threaded applications then that topic is too complex by far for a single stackoverflow answer.

Regarding the question why MS recommends to use IDirect3DDeviceManager9 ... well, I'm not aware of such a general recommendation. It's just recommended when doing video processing (using DXVA, the EVR etc.). Or more like mandated; I'm not sure if you can share the D3D device with e.g. the Enhanced Video Renderer without using the D3D device manager. That's what the D3D device manager was made for after all. With the VMR9 sharing a device with the renderer was only possible in two ways:

The documented way: only ever access the device from the "present" callback of the VMR9. Which is rather limiting - e.g. you're limited to the frame rate of the video.

The undocumented way: do NOT call IVMRFilterConfig9::SetNumberOfStreams and only connect one input stream. That way VMR9 will not switch to "mixer mode", and when not in "mixer mode" VMR9 will not change any device states. So if the D3D device was initialized multithreaded, then you can use the D3D device freely while VMR9 is using the same device.

Also with the VMR9 it was not possible to use the D3D device in another DirectShow filter at all. The D3D device manager improves upon that, giving filters and your own application code the ability to use the D3D device - including changing states. If however you implement every component that will use the D3D device yourself, then there's not really any point in usind the D3D device manager. And even if you're using third-party components that require a D3D device you will only be able to use the D3D device manager if those components support it. Which will probably not be the case unless those components happen to be DirectShow or MediaFoundation filters/components.

like image 61
Paul Groke Avatar answered Oct 06 '22 17:10

Paul Groke