不好

C Language Problems in Direct3D 12 — GetCPUDescriptor­Handle­For­HeapStart

by Josh Staiger

August 10, 2020

There is a bug in the Microsoft-provided d3d12.h C language definitions for ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart and ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart.

The Problem

When compiling a .c file in x64 with the original header declaration I do:

_rtvHeap: *ID3D12DescriptorHeap;

D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = _rtvHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(_rtvHeap);

This succeeds, but returns (what turns out to be) an incorrect pointer for the HeapStart.

And this causes a crash later when calling ID3D12Device::CreateRenderTargetView with the returned rtvHandle, leaving the following error in the D3d12 debug layer output:

D3D12 ERROR: ID3D12Device::CreateRenderTargetView: Specified CPU descriptor handle ptr=... does not refer to a location in a descriptor heap.  [ EXECUTION ERROR #646: INVALID_DESCRIPTOR_HANDLE]

The Fix

The Microsoft-provided d3d12.h contains these declarations:

typedef struct ID3D12DescriptorHeapVtbl {
..

    D3D12_CPU_DESCRIPTOR_HANDLE ( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )( 
        ID3D12DescriptorHeap * This);

    D3D12_GPU_DESCRIPTOR_HANDLE ( STDMETHODCALLTYPE *GetGPUDescriptorHandleForHeapStart )( 
        ID3D12DescriptorHeap * This);

..
} ID3D12DescriptorHeapVtbl;

In both cases, the result should be passed as an output parameter, rather than a return value.

typedef struct ID3D12DescriptorHeapVtbl {
..
    void ( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )( 
        ID3D12DescriptorHeap * This, D3D12_CPU_DESCRIPTOR_HANDLE *result);

    void ( STDMETHODCALLTYPE *GetGPUDescriptorHandleForHeapStart )( 
        ID3D12DescriptorHeap * This, D3D12_GPU_DESCRIPTOR_HANDLE *result);
..
} ID3D12DescriptorHeapVtbl;

Thanks to Cara Ames for this answer at StackOverflow that helped me track this down: GetCPUDescriptorHandleForHeapStart stack corruption .

hi@joshstaiger.org