#pragma once #include #include "com_include.h" #include "../util_likely.h" namespace dxvk { template class NoWrapper : public T { public: virtual ~NoWrapper() { } }; /** * \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 { public: virtual ~ComObject() { } ULONG STDMETHODCALLTYPE AddRef() { uint32_t refCount = m_refCount++; if (unlikely(!refCount)) AddRefPrivate(); return refCount + 1; } ULONG STDMETHODCALLTYPE Release() { uint32_t refCount = --m_refCount; if (unlikely(!refCount)) ReleasePrivate(); return refCount; } void AddRefPrivate() { ++m_refPrivate; } void ReleasePrivate() { uint32_t refPrivate = --m_refPrivate; if (unlikely(!refPrivate)) { m_refPrivate += 0x80000000; delete this; } } ULONG GetPrivateRefCount() const { return m_refPrivate.load(); } bool HasLiveReferences() const { return bool(m_refCount.load() | (m_refPrivate.load() & 0x7FFFFFFF)); } protected: std::atomic m_refCount = { 0ul }; std::atomic m_refPrivate = { 0ul }; }; /** * \brief Clamped, reference-counted COM object * * This version of ComObject ensures that the reference * count does not wrap around if a release happens at zero. * eg. [m_refCount = 0] * Release() * [m_refCount = 0] * This is a notable quirk of D3D9's COM implementation * and is relied upon by some games. */ template class ComObjectClamp : public ComObject { public: ULONG STDMETHODCALLTYPE Release() { ULONG refCount = this->m_refCount; if (likely(refCount != 0ul)) { this->m_refCount--; refCount--; if (refCount == 0ul) this->ReleasePrivate(); } return refCount; } }; template inline void InitReturnPtr(T** ptr) { if (ptr != nullptr) *ptr = nullptr; } }