Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access violation when calling ID3D12DescriptorHeap.GetCPUDescriptorHandleForHeapStart #449

Closed
ghord opened this issue Nov 10, 2021 · 5 comments
Labels
bug Something isn't working

Comments

@ghord
Copy link

ghord commented Nov 10, 2021

Actual behavior

I'm getting access violation error when calling ID3D12DescriptorHeap.GetCPUDescriptorHandleForHeapStart method. I've destilled my code to short repro. It might be my error, but C++ version looks to be working without crashing.

Expected behavior

Code working correctly

Repro steps

  1. NativeMethods.txt content:
D3D12CreateDevice
ID3D12Device
ID3D12DescriptorHeap
  1. NativeMethods.json content (if present):
{
  "$schmea": "https://aka.ms/CsWin32.schema.json",
  "allowMarshaling": false,
}

NOTE: I've tried different settings and could not manage to get it to work without access violation. I've also tried version with and without marshalling.

  1. Any of your own code that should be shared?
    static unsafe void Main()
    {
        void* result;

        var uuid_ID3D12Device = typeof(ID3D12Device).GUID;
        PInvoke.D3D12CreateDevice(null, Windows.Win32.Graphics.Direct3D11.D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_12_0, &uuid_ID3D12Device, &result);

        var device = (ID3D12Device*)result;

        D3D12_DESCRIPTOR_HEAP_DESC desc;

        desc.NumDescriptors = 1;
        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE.D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
        desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS.D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
        desc.NodeMask = 0;

        var uuid_ID3D12DescriptorHeap = typeof(ID3D12DescriptorHeap).GUID;

        device->CreateDescriptorHeap(&desc, &uuid_ID3D12DescriptorHeap, &result);

        var heap = (ID3D12DescriptorHeap*)result;

        //Throws Access Violation
        heap->GetCPUDescriptorHandleForHeapStart();

    }

Here is the version with marshalling enabled:

    static void Main()
    {
        object result;

        var uuid_ID3D12Device = typeof(ID3D12Device).GUID;
        PInvoke.D3D12CreateDevice(null, Windows.Win32.Graphics.Direct3D11.D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_12_0, uuid_ID3D12Device, out result);

        var device = (ID3D12Device)result;

        D3D12_DESCRIPTOR_HEAP_DESC desc;

        desc.NumDescriptors = 1;
        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE.D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
        desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS.D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
        desc.NodeMask = 0;

        var uuid_ID3D12DescriptorHeap = typeof(ID3D12DescriptorHeap).GUID;

        device.CreateDescriptorHeap(desc, uuid_ID3D12DescriptorHeap, out result);

        var heap = (ID3D12DescriptorHeap)result;

        //Throws Access Violation
        heap.GetCPUDescriptorHandleForHeapStart();

    }

Compare to correclty working C++ version:

#include <Windows.h>
#include <D3D12.h>
int main(int argc, char** argv)
{

	ID3D12Device *device;
	if(!SUCCEEDED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, __uuidof(ID3D12Device), (void**) & device)))
		return -1;

	D3D12_DESCRIPTOR_HEAP_DESC desc;
	desc.NumDescriptors = 1;
	desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE::D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
	desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAGS::D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	desc.NodeMask = 0;
		
	
	ID3D12DescriptorHeap* heap;
	if(!SUCCEEDED(device->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void**)&heap)))
		return -1;

	auto handle = heap->GetCPUDescriptorHandleForHeapStart();

	
}

Context

  • CsWin32 version: 0.1.588-beta
  • Target Framework: net6.0-windows
@ghord ghord added the bug Something isn't working label Nov 10, 2021
@ghord
Copy link
Author

ghord commented Nov 10, 2021

I guess this is the same issue as in #167 . Is there any recommended workaround for now?

@AArnott
Copy link
Member

AArnott commented Nov 10, 2021

I don't have a workaround to offer at this point. Thanks for the report and noticing the dupe.

@ghord
Copy link
Author

ghord commented Nov 10, 2021

I did some more digging and it appears that support for this calling convention is already implemented in clr in .net 6. Since I'm already using it, I was able to work around this issue with following code (code is proof of concept for now, performance of this is very bad obviously):

    private unsafe D3D12_CPU_DESCRIPTOR_HANDLE GetDescriptorHandle(ID3D12DescriptorHeap* heap)
    {
        var vtableField = typeof(ID3D12DescriptorHeap).GetField("lpVtbl", BindingFlags.NonPublic | BindingFlags.Instance)!;
        var vtableType = typeof(ID3D12DescriptorHeap).GetNestedType("Vtbl", BindingFlags.NonPublic)!;

        var vtable = (nuint*)Pointer.Unbox(vtableField.GetValue(*heap));

        var getDescriptor = (delegate* unmanaged[Stdcall, MemberFunction]<ID3D12DescriptorHeap*, D3D12_CPU_DESCRIPTOR_HANDLE>)(vtable[9]);

        var getDescriptorResult = getDescriptor(heap);

        return getDescriptorResult;
    }

This code requires marshalling to be disabled and manually calls the vtable pointer with newly introduced MemberFunction calling convention annotation instead. I've done some testing and it seems to resolve the issue.

Is there a plan to use this new COM calling convention in generated vtables?

@AArnott
Copy link
Member

AArnott commented Nov 10, 2021

Is there a plan to use this new COM calling convention in generated vtables?

Not at present. Presumably there should be a way to make this work on .NET Framework as well, and we'd most likely generate the code necessary to make it work there as well as .NET 6.

@AArnott
Copy link
Member

AArnott commented Jun 16, 2022

Closing as duplicate of #167.

@AArnott AArnott closed this as not planned Won't fix, can't repro, duplicate, stale Jun 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants