Exception while creating D3D12_CPU_DESCRIPTOR_HANDLE

Started by
6 comments, last by Jason Smith 6 years ago

While working on a project using D3D12 I was getting an exception being thrown while trying to get a D3D12_CPU_DESCRIPTOR_HANDLE. The project is using plain C so it uses the COBJMACROS. The following application replicates the problem happening in the project.



#define COBJMACROS
#pragma warning(push, 3)
#include <Windows.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#pragma warning(pop)

IDXGIFactory4 *factory;
ID3D12Device *device;
ID3D12DescriptorHeap *rtv_heap;

int WINAPI
wWinMain(HINSTANCE hinst, HINSTANCE pinst, PWSTR cline, int cshow) {
    (hinst), (pinst), (cline), (cshow);

  	HRESULT hr = CreateDXGIFactory1(&IID_IDXGIFactory4, (void **)&factory);
    hr = D3D12CreateDevice(0, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &device);

    D3D12_DESCRIPTOR_HEAP_DESC desc;
    desc.NumDescriptors = 1;
    desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    desc.NodeMask = 0;
    hr = ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, (void **)&rtv_heap);
    D3D12_CPU_DESCRIPTOR_HANDLE rtv = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_heap);
    (rtv);
}

The call to ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart throws an exception. Stepping into the disassembly for ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart show that the error occurs on the instruction

mov  qword ptr [rdx],rax

which seems odd since rdx doesn't appear to be used. Any help would be greatly appreciated. Thank you.

 

Advertisement

Does ID3D12Device_CreateDescriptorHeap succeed or fail?

S_OK for all HRESULTs

Maybe there's a bug when creating a heap with only 1 descriptor?

Either way, you should enable the debug validation layer and see if it reports any errors in the debugger output window. You can also set the debug layer to break into the debugger on an error or warning, which can make it easier to locate the code that's causing an error.

14 minutes ago, MJP said:

Maybe there's a bug when creating a heap with only 1 descriptor?

Either way, you should enable the debug validation layer and see if it reports any errors in the debugger output window. You can also set the debug layer to break into the debugger on an error or warning, which can make it easier to locate the code that's causing an error.

Hey MJP thanks for the reply. The snippet in the original post was just made as simple as possible to illustrate the problem that is occurring in a larger project. Just to be sure though I tried all these in the simple app as well. Multiple descriptors in the heap doesn't change anything. Enabling the debug layer give no additional information.

Here is the relevant disassembly:


D3D12_CPU_DESCRIPTOR_HANDLE rtv = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_heap);
mov         rax,qword ptr [rtv_heap (07FF721616410h)]  
mov         rax,qword ptr [rax]  
mov         rcx,qword ptr [rtv_heap (07FF721616410h)]  
call        qword ptr [rax+48h]  

NDebug::CDescriptorHeap::GetCPUDescriptorHandleForHeapStart:
mov         rax,qword ptr [rcx+0E8h]  
mov         qword ptr [rdx],rax  // This is were exception is thrown

Exception thrown at 0x00007FFCCF77FCF7 (d3d12SDKLayers.dll) in win32_fw_init.exe: 0xC0000005: Access violation writing location 0x00007FFCD843ED90.

This is a known issue. Turns out that the C++ function implementations don't match the C function definitions, specifically when returning structures larger than one pointer. The workaround is to cast the functions to what their implementation really looks like before calling them. Example with ID3D12DescriptorHeap::GetDesc:


((void (__stdcall*)(ID3D12DescriptorHeap*, D3D12_DESCRIPTOR_HEAP_DESC*)) mDescriptorHeap->lpVtbl->GetDesc)(mDescriptorHeap, &debugdescHeap);

Basically, the way MSVC implements __stdcall when returning large structs is to hoist it to an out parameter for C++, but I'm pretty sure that the C compiler chooses a different calling convention entirely.

My suggestion: don't use C.

Hey Soldier, that seems to be it. Thank you.

After seeing your post I was able to find the following references for anyone interested that is having this problem.

Just Let It Flow

Stack Overflow

Not using C would be the easy solution but that means using the garbage that is C++.

This topic is closed to new replies.

Advertisement