diff --git a/src/util/com/com_object.h b/src/util/com/com_object.h index fdd00fc5..54304b0c 100644 --- a/src/util/com/com_object.h +++ b/src/util/com/com_object.h @@ -6,6 +6,22 @@ namespace dxvk { + /** + * \brief Reference-counted COM object + * + * This can serve as a templated base class for most + * COM objects. It implements AddRef and Release from + * \c IUnknown, and provides methods to increment and + * decrement private references which are not visible + * to the application. + * + * Having two reference counters is sadly necessary + * in order to not break games which steal internal + * references if the refefence count of an object is + + greater than they expect. DXVK sometimes requires + * holding on to objects which the application wants + * to delete. + */ template class ComObject : public Base... { @@ -14,21 +30,36 @@ namespace dxvk { virtual ~ComObject() { } ULONG STDMETHODCALLTYPE AddRef() { - return ++m_refCount; + ULONG refCount = m_refCount++; + if (refCount == 0ul) + AddRefPrivate(); + return refCount; } ULONG STDMETHODCALLTYPE Release() { ULONG refCount = --m_refCount; - if (refCount == 0) { - m_refCount += 0x80000000u; + if (refCount == 0ul) + ReleasePrivate(); + return refCount; + } + + + void AddRefPrivate() { + ++m_refPrivate; + } + + + void ReleasePrivate() { + if (--m_refPrivate == 0ul) { + m_refPrivate += 0x80000000; delete this; } - return refCount; } private: - std::atomic m_refCount = { 0ul }; + std::atomic m_refCount = { 0ul }; + std::atomic m_refPrivate = { 0ul }; };