1

I am making a simple d3d 11 application and I'm using the Microsoft::WRL::ComPtr to release the resources automatically. For some reason though when the applications exits I'm getting 30-40 Live Object warnings from d3d. I could have missed one or two, but this seems more like the count of all objects I have. I'm obviously doing something wrong. My general usage would be to have a member in some wrapper class:

class graphics_device
{
   // ...
   ComPtr<ID3D11Device> hwdevice;
}

Which in theory should release the object upon class destruction. (I'm creating most objects on stack and I've double checked that I delete the ones that are on the heap)

When I create my functionality I pass them around as references. For example:

void graphics_device::create_constant_buffer(u32 size, const void* data, ComPtr<ID3D11Buffer>& constantBuffer)
{
    D3D11_BUFFER_DESC bufferDesc;
    ZeroMemory(&bufferDesc, sizeof(bufferDesc));

    bufferDesc.Usage = D3D11_USAGE_DEFAULT;
    bufferDesc.ByteWidth = size;
    bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bufferDesc.CPUAccessFlags = 0;

    D3D11_SUBRESOURCE_DATA initData;
    ZeroMemory(&initData, sizeof(initData));
    initData.pSysMem = data;

    device->CreateBuffer(&bufferDesc, &initData, &constantBuffer);
}

Any ideas what I'm missing?

EDIT: Forgot to post the warnings from d3d11:

D3D11 WARNING:  Live Object at 0x0061D93C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x0061DBE4, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING:  Live Object at 0x0061DE8C, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
D3D11 WARNING: Live                         Object :     31 [ STATE_CREATION WARNING #0: UNKNOWN]
DXGI WARNING: Live Producer at 0x005ADDC0, Refcount: 4. [ STATE_CREATION WARNING #0: ]
DXGI WARNING:   Live Object at 0x005B7FD0, Refcount: 2. [ STATE_CREATION WARNING #0: ]
DXGI WARNING: Live                         Object :      1 [ STATE_CREATION WARNING #0: ]

And many more similar. I'm not getting any other warnings during runtime.

Gregor Sattel
  • 352
  • 3
  • 12
  • 1
    ComPtr should not leak anything. Do you have a reproducing project? Have you ran in Debug mode (F5) ? Note one object can reference a lot of others by cascading references, and also you can name object to determine who allocated them: https://walbourn.github.io/object-naming/ – Simon Mourier Apr 26 '21 at 18:18
  • Great idea, I'll try to name to see whats what - maybe that will give me some clarity. Also found this question that might have something in common that I'll read through tomorrow: https://stackoverflow.com/questions/20032816/can-someone-explain-why-i-still-have-live-objects-after-releasing-the-pointers-t – Gregor Sattel Apr 26 '21 at 19:04

1 Answers1

2

Getting a 'clean exit' can be a little challenging. It's not likely to be ComPtr if used correctly. Per the comment, a good place to start is object naming. Remember that the output happens when the Direct3D Device is released, so you may need to look at the 'release order' to get it to cleanly exit. There are also 'internal' vs. 'external' ref-counts so they can be a little confusing. See this blog post for some notes on the debug layer usage.

Another thing to keep in mind is that Direct3D object reporting can't really tell you about DXGI-owned objects. That's why also using DXGI Debug Device can be useful as well.

The directx-vs-templates put all advice from these blog posts in one place, so you might want to look at them.

Finally, passing ComPtr as a parameter is generally not the best use case even by reference. Using ComPtr as data members and local variables is great, but usually as parameters it's best to use "raw pointers" since the lifetime is implicit already. So your function signature would be better as:

void graphics_device::create_constant_buffer(u32 size, const void* data, ID3D11Buffer** constantBuffer);

Then when calling that function, you use a ComPtr:

ComPtr<ID3D11Buffer> cb;
graphicsdevice->create_constant_buffer(size, data, &cb);

See this wiki on ComPtr for some hints on using it most effectively.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Why is it bad idea to pass ComPtr as reference? This would not create a new copy (thus increasing ref counts), right? I find it convenient since I can manage the raw data in my wrapper and not care about it in the implementation. If I pass raw pointers I'll have to keep in mind each time when to release and when only to get the raw pointer. – Gregor Sattel Apr 29 '21 at 06:12
  • 1
    (a) if you write your functions using raw pointers, you are not forcing the client of your function to use a particular smart-pointer, (b) in functions where you would be passing the raw pointer, the lifetime is already implicit so there's no reason you'd need to change the reference count in the first place, (c) in 'factory' functions the class-creating function is already returning a ref count of 1, and (d) if you forget to use by-ref it will cost you a useless refcount cycle every call. I use ComPtr all over the place... I just find it better to use it for data and not for parameters – Chuck Walbourn Apr 29 '21 at 07:52
  • Thanks for the detailed explanation :) – Gregor Sattel Apr 29 '21 at 08:17