2
votes

Based on the MSDN for Direct 3D 11 Graphics the documentation section "How to create an immediate context" shows the following code:

ID3D11Texture2D* pBackBuffer;
// Get a pointer to the back buffer
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ),
( LPVOID* )&pBackBuffer );

The here called pBackBuffer is of Type ID3D11Texture2D. The documentation for the GetBuffer method (https://docs.microsoft.com/en-gb/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-getbuffer) describes the second Parameter as Type REFIID (The type of interface used to manipulate the buffer) and the third as void** A pointer to a back-buffer interface.

Now a different section in the documentation about Direct2d shows the following snippet to write Direct2d content to a Direct3d buffer:

 hr = m_pSwapChain->GetBuffer(
        0,
        IID_PPV_ARGS(&pBackBuffer)
        );

Here the BackBuffer is used in CreateDxgiSurfaceRenderTarget as first parameter which is a IDXGISurface which means the Backbuffer that I got is an IDXGISurface.

How do I know that I can pass in ID3D11Texture2D and IDXGISurface to that GetBuffer method when the MSDN only describes the parameter as REFIID (see above) ? And how can I figure out what elese I can pass in there?

1
If it's not documented, you don't know. There are discovery mechanisms in COM but they are rarely implemented. One thing you know is, in general, you can get the different version of an interface from one of the version. ie: you can get IBlah from IBlah2 (and the reverse if the system supports it). But from a Texture to a Surface, it has to be documented. The last resort is to disassemble the .dll with a tool such as IDA and it will tell you what are the implemented interfaces if the PDBs are available ... - Simon Mourier
Note that IID_PPV_ARGS(&pBackBuffer) is just a preprocessor macro wrapper that resolves to __uuidof(*pBackBuffer), ( LPVOID* )&pBackBuffer. See COM Coding Practices: The IID_PPV_ARGS Macro - Remy Lebeau
The REFIID is crucial, it describes the type of interface pointer reference you pass as the 3rd argument. So crucial that they came up with the IID_PPV_ARGS macro to auto-generate the 2nd and 3rd arguments. In other words, there is no distinction between the two snippets, just written differently. You'll know it can't supply the interface from the hr return value. - Hans Passant
All three comments above are great. To add a bit, if you absolutely need to know what else can be requested, you'd step into the call with debugger in disassembly mode and check that IID argument is being compared to. This is a sort of last resort, but sometimes if what's indeed being done. - Roman R.
Thanks for all the answers! I will take a look at it with a debugger and see what comes up. But so far I guess I need to rely on the documentation and what is there - user7145038

1 Answers

0
votes

TL;DR: Read the Microsoft Docs article Programming DirectX with COM.

The DirectX APIs use a "lite" form of COM, so they don't fully implement all the possible features the Component Object Model (COM):

  • They use reference counting for lifetime using IUnknown but this a modified form where IDeviceChild objects will all be immediately invalid when their parent IDevice interface is fully released. You can use AddRef and Release, although for C++ you are better off using something like ComPtr.

  • DirectX APIs don't support "single-threaded apartment"

  • Some DirectX APIs do not support CoCreateInstance and have to be created via a specific factory API.

  • They do not implement aggregation.

  • DirectX APIs don't generally implement out-of-process/remote process behavior

To your question, DirectX APIs generally support a limited number of interfaces and you use QueryInterface to 'down-cast' them. A given DirectX object will support IUnknown, and the IID for each class in the hierarchy on that system (i.e. if it's ID3D11Device2 then it will support ID3D11Device1 and ID3D11Device). With C++, you typically just use inheritance to go up the hierarchy but you can use QueryInterface.

Otherwise, there are only going to be a few specific cases of objects supporting multiple interfaces, such as DXGI interop with Direct3D for swapchains or device-shared textures. In other words, most cases result in E_NOINTERACE.

See also The Component Object Model and Reference Counting (Direct3D 10),