diff --git a/src/util/com/com_object.h b/src/util/com/com_object.h index 48518fe24..75188d5c1 100644 --- a/src/util/com/com_object.h +++ b/src/util/com/com_object.h @@ -72,12 +72,43 @@ namespace dxvk { return m_refPrivate.load(); } - private: + 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) {