3

D3D12CreateDevice in the following code throws a _com_error exception even if an adapter is specified:

#include "d3dx12.h"

int main() {
    ID3D12Device* device;
    D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
}

Exception thrown at 0x00007FFB1E315549 in test.exe: Microsoft C++ exception: _com_error at memory location 0x0000002906BC90E0.

But this sample program from Microsoft is not throwing _com_error from D3D12CreateDevice. D3D12CreateDevice behavior is weird because if I rename HelloTriangle folder to HelloTriangle2, exception reappears.

I checked the HRESULT from D3D12CreateDevice, and it returns 0(ZERO) which is successful. But I still get _com_error. My adapter supports DX12 by hardware.

volodya7292
  • 454
  • 8
  • 20

1 Answers1

2

Exceptions can be used internally by the runtime, and as long as they are not propagated out of the function that's still correct. If you continue from that exception, it will likely return. You aren't checking the HRESULT from D3D12CreateDevice, which you should do to see what it's returning.

The primary difference is that the sample code is using an explicitly enumerated adapter which been verified to support Direct3D 12, while your code relies on the default device.

// Helper function for acquiring the first available hardware adapter that supports Direct3D 12.
// If no such adapter can be found, *ppAdapter will be set to nullptr.
_Use_decl_annotations_
void DXSample::GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter)
{
    ComPtr<IDXGIAdapter1> adapter;
    *ppAdapter = nullptr;

    for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter); ++adapterIndex)
    {
        DXGI_ADAPTER_DESC1 desc;
        adapter->GetDesc1(&desc);

        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
        {
            // Don't select the Basic Render Driver adapter.
            // If you want a software adapter, pass in "/warp" on the command line.
            continue;
        }

        // Check to see if the adapter supports Direct3D 12, but don't create the
        // actual device yet.
        if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
        {
            break;
        }
    }

    *ppAdapter = adapter.Detach();
}

If your system does not have a Direct3D 12 capable device, then the sample code is then using the WARP software device which your code is also not doing.

So it is possible that your default video device does not support Direct3D 12, and you may not even have any video device on your system that supports it. That said, C++ exceptions thrown inside the Direct3D runtime can still trigger a debugger break so you have to continue them.

See Anatomy of Direct3D 12 Create Device for a detailed walkthrough of creating a Direct3D 12 device.

You may also want to make use of DeviceResources to handle all the logic for device creation.

Varaquilex
  • 3,447
  • 7
  • 40
  • 60
Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • 1
    I checked the HRESULT from D3D12CreateDevice, and it returns 0(ZERO) which is successful. But I still get _com_error. I have one adapter and it supports DX12 by hardware – volodya7292 Feb 04 '19 at 18:51
  • Ok. As I said, C++ exceptions internal to the component is expected behavior as long as no exception propagates outside of the function. – Chuck Walbourn Feb 04 '19 at 19:18
  • 1
    Judging by symptoms the exceptions are very likely to be related to D3D shader cache. They are internal but they are annoying. It would be great to have a hint how to work them around. Unfortunately this answer in its current state leads away from the problem. – Roman R. Feb 08 '19 at 08:35