Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3D11 increased ref count from nowhere?

I have been working with d3d11 for quite a while now, and after discovering the directx debugger, i've recently discovered that my program is leaking memory everywhere from all the com objects that aren't releasing properly. After a bit of snooping around and hours of staring at the code, i've developed some methods to isolate where i'm getting these unexpected increases to the ref counts.

first off, all of the objects are wrapped in std::shared_ptrs with custom deleters that call their respective release function. I did this so i would never have to call addref, and the first call to release, the one in the deleter, would only be called when the object went out of scope. It would look something like this:

// in D3D11Renderer.h
...
// declaration
std::shared_ptr<ID3D11Device *> m_Device;
...

// after call to ID3D11CreateDeviceAndSwapChain
m_Device.reset(device, [](ID3D11Device * ptr){ptr->Release();})

Problem is certain random functions in the api calls will just randomly increase the ref count, expecting me to have to deal with it later.

something i found useful in diagnosis was a function that looked like this:

template <typename T>
int getRefCount(T object) 
{
    object->AddRef();
    return object->Release();
}

which, just increments and decrements that count to obtain the current count of refs on that object. Using this, i found that, just before the release in the custom deleter is called, there are 10 outstanding references to the 1 ID3D11Device i created. Curious, i backtracked slowly, calling this function all the way back through the program, right up to where i originally created it. Funny thing, just after i first create the object, (even before the shared_ptr takes ownership), the number of outstanding refs is already 3! This occurs immediately after this here.

result = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1, 
                           D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, NULL, &deviceContext);
    if(FAILED(result))
    {
        return false;
    }

this is the first time i call any such function that creates the device, and when i check to see how many refs there are right after, and it says 3! So clearly, I'm misunderstanding something about the way these com objects are supposed to be handled. Is there any such way that i can just manually delete them, rather then use there behind-the-scenes ref counting nonsense?

like image 283
FatalCatharsis Avatar asked Nov 20 '25 13:11

FatalCatharsis


1 Answers

Every time you create a buffer or a shader or anything that depends on the device, that object will likely contain a reference to the device so will bump up it's reference count to ensure it's not deleted while it is still using it.

It sounds like your approach might well work overall, as you'll essentially keep one single reference to the device in your code to stop it being deleted, and when all your internal references are gone release it. However d3d will still be doing it's own reference counting and so the reference count will only drop to zero when you release every reference to every other related object. Even just creating the swap chain and device will make back buffers and so on that likely need to maintain a reference to the device.

I tried this same idea for a while... And in the end found it much easier to just

#include <atlbase>

Then use

CComPtr<ID311Device> m_Device

as that's pretty much exactly what that class is designed for and it's more lightweight than std::shader_ptr as the objects already have a reference counter in them so there is no need to keep a separate one.

like image 189
jcoder Avatar answered Nov 23 '25 04:11

jcoder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!