From d4cad9055cc89a582a8f0afe96f33b54a2f7f920 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sun, 2 Jun 2019 00:14:54 +0100 Subject: [PATCH] [util] Implement a clamped version of ComObject, for D3D9 Satisfies a quirk in D3D9, solving an issue in SWTFU. --- src/util/com/com_object.h | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) 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) {