2

I am trying to follow Microsoft's official tutorial for DirectX and XAML interop in order to make a C++ runtime library for image primitive drawing for a UWP application. However, the code is riddled with bugs and typos. I have managed to adapt portions of it, but I am getting runtime errors.

I have adapted the code as follows.

Microsoft::WRL::ComPtr<ISurfaceImageSourceNativeWithD2D> m_sisNativeWithD2D;

IInspectable* sisInspectable = (IInspectable*) reinterpret_cast<IInspectable*>(surfaceImageSource);
sisInspectable->QueryInterface(__uuidof(ISurfaceImageSourceNativeWithD2D), (void **)&m_sisNativeWithD2D);

Microsoft::WRL::ComPtr<ID3D11Device> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_d3dContext;
Microsoft::WRL::ComPtr<ID2D1Device> m_d2dDevice;

// Create the DXGI device
D3D11CreateDevice(
    NULL,
    D3D_DRIVER_TYPE_HARDWARE,
    NULL,
    0,
    NULL,
    NULL,
    D3D11_SDK_VERSION,
    &m_d3dDevice,
    NULL,
    &m_d3dContext);

Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);

// To enable multi-threaded access (optional)
Microsoft::WRL::ComPtr<ID3D10Multithread> d3dMultiThread;

m_d3dDevice->QueryInterface(__uuidof(ID3D10Multithread), (void **)&d3dMultiThread);

d3dMultiThread->SetMultithreadProtected(TRUE);

// Create the D2D device
HRESULT d2d1 = D2D1CreateDevice(dxgiDevice.Get(), NULL, &m_d2dDevice);

While debugging the code, I can see that the d2d1 handle is returning E_INVALIDARG. I tried passing device properties instead of NULL and disabling multi-threaded access, but the error persists. Objects before this line seem to be correctly initialized.

What could be causing this behavior?

Edit

VTT's comment helped in constructing the device, but it seems that the device is not appropriate. My adapted code is as follows.

Microsoft::WRL::ComPtr<ISurfaceImageSourceNativeWithD2D> m_sisNativeWithD2D;

IInspectable* sisInspectable = (IInspectable*) reinterpret_cast<IInspectable*>(surfaceImageSource);
sisInspectable->QueryInterface(__uuidof(ISurfaceImageSourceNativeWithD2D), (void **)&m_sisNativeWithD2D);

Microsoft::WRL::ComPtr<ID3D11Device> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_d3dContext;
Microsoft::WRL::ComPtr<ID2D1Device> m_d2dDevice;

D3D_FEATURE_LEVEL array[] = {
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
    D3D_FEATURE_LEVEL_9_3,
    D3D_FEATURE_LEVEL_9_2,
    D3D_FEATURE_LEVEL_9_1,
};

D3D_FEATURE_LEVEL selectedFeatureLevel;

// Create the DXGI device
D3D11CreateDevice(
    NULL,
    D3D_DRIVER_TYPE_HARDWARE,
    NULL,
    D3D11_CREATE_DEVICE_BGRA_SUPPORT,
    array,
    sizeof(array)/sizeof(D3D_FEATURE_LEVEL),
    D3D11_SDK_VERSION,
    &m_d3dDevice,
    &selectedFeatureLevel,
    &m_d3dContext);

//Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
//m_d3dDevice.As(&dxgiDevice);

Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
auto hr = m_d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);

// To enable multi-threaded access (optional)
Microsoft::WRL::ComPtr<ID3D10Multithread> d3dMultiThread;
m_d3dDevice->QueryInterface(__uuidof(ID3D10Multithread), (void **)&d3dMultiThread);
d3dMultiThread->SetMultithreadProtected(TRUE);

// Create the D2D device
HRESULT d2d1 = D2D1CreateDevice(dxgiDevice.Get(), NULL, &m_d2dDevice);

// Set the D2D device
m_sisNativeWithD2D->SetDevice(m_d2dDevice.Get());

Microsoft::WRL::ComPtr<ID2D1DeviceContext> drawingContext;

RECT rect;
rect.top = 0;
rect.left = 0;
rect.right = 50;
rect.bottom = 50;

POINT offset;

HRESULT beginDrawHR = m_sisNativeWithD2D->BeginDraw(rect, __uuidof(ID2D1DeviceContext), &drawingContext, &offset);

However, here the BeginDraw() method fails with E_INVALIDARG. I am assuming it is because of the incorrect device construction.

Igor Ševo
  • 5,459
  • 3
  • 35
  • 80
  • 1
    It looks like you are avoiding to pass reasonable values into `D3D11CreateDevice` constructor. For d2d compatibility you need to pass at least `D3D11_CREATE_DEVICE_BGRA_SUPPORT` flag and appropriate feature_levels array. Also letting it auto select adapter is usually not a good idea, typically you want to use the adapter to which the target output belongs to. – user7860670 May 01 '17 at 09:47
  • @VTT I have created the object by passing the flags and feature levels array. The problem seems to be resolved, but I would like to pass the adapter to the constructor. How would you go about constructing the appropriate one? I tried to use the `IDXGIFactory` and enumerate adapters, but `m_d3dDevice.As(&dxgiDevice);` fails with every one. – Igor Ševo May 01 '17 at 10:09
  • Does `m_sisNativeWithD2D->SetDevice` call succeed? Is surfaceImageSource already displayed when you call this code? – user7860670 May 02 '17 at 08:31
  • `SetDevice()` returns `S_OK`. The caller code is in C# and the `SurfaceImageSource` is assigned as source of an image component visible in the window. – Igor Ševo May 02 '17 at 11:17

0 Answers0