2017-10-11 00:41:56 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
|
|
#include "com_include.h"
|
2019-06-02 23:34:53 +02:00
|
|
|
|
|
|
|
#include "../util_likely.h"
|
2017-12-10 00:55:30 +01:00
|
|
|
|
2017-10-11 00:41:56 +02:00
|
|
|
namespace dxvk {
|
|
|
|
|
2019-10-14 01:43:47 +02:00
|
|
|
template<typename T>
|
2019-10-25 22:08:00 +02:00
|
|
|
class NoWrapper : public T {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual ~NoWrapper() { }
|
|
|
|
|
|
|
|
};
|
2019-10-14 01:43:47 +02:00
|
|
|
|
2018-08-05 16:38:31 +02:00
|
|
|
/**
|
|
|
|
* \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.
|
|
|
|
*/
|
2019-10-14 01:42:07 +02:00
|
|
|
template<typename Base>
|
|
|
|
class ComObject : public Base {
|
2017-10-11 00:41:56 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual ~ComObject() { }
|
|
|
|
|
2017-12-12 12:50:52 +01:00
|
|
|
ULONG STDMETHODCALLTYPE AddRef() {
|
2019-06-02 23:34:53 +02:00
|
|
|
uint32_t refCount = m_refCount++;
|
|
|
|
if (unlikely(!refCount))
|
2018-08-05 16:38:31 +02:00
|
|
|
AddRefPrivate();
|
2019-06-01 22:12:32 +02:00
|
|
|
return refCount + 1;
|
2017-10-11 00:41:56 +02:00
|
|
|
}
|
|
|
|
|
2017-12-12 12:50:52 +01:00
|
|
|
ULONG STDMETHODCALLTYPE Release() {
|
2019-06-02 23:34:53 +02:00
|
|
|
uint32_t refCount = --m_refCount;
|
|
|
|
if (unlikely(!refCount))
|
2018-08-05 16:38:31 +02:00
|
|
|
ReleasePrivate();
|
|
|
|
return refCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AddRefPrivate() {
|
|
|
|
++m_refPrivate;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReleasePrivate() {
|
2019-06-02 23:34:53 +02:00
|
|
|
uint32_t refPrivate = --m_refPrivate;
|
|
|
|
if (unlikely(!refPrivate)) {
|
2018-08-05 16:38:31 +02:00
|
|
|
m_refPrivate += 0x80000000;
|
2017-10-11 00:41:56 +02:00
|
|
|
delete this;
|
2017-12-09 22:20:40 +01:00
|
|
|
}
|
2017-10-11 00:41:56 +02:00
|
|
|
}
|
2019-05-01 20:04:07 +01:00
|
|
|
|
2023-06-24 12:35:31 +02:00
|
|
|
ULONG GetPrivateRefCount() const {
|
2019-05-01 20:04:07 +01:00
|
|
|
return m_refPrivate.load();
|
|
|
|
}
|
2023-06-24 12:35:31 +02:00
|
|
|
|
|
|
|
bool HasLiveReferences() const {
|
2023-06-24 12:45:38 +02:00
|
|
|
return bool(m_refCount.load() | (m_refPrivate.load() & 0x7FFFFFFF));
|
2023-06-24 12:35:31 +02:00
|
|
|
}
|
|
|
|
|
2019-06-02 00:14:54 +01:00
|
|
|
protected:
|
2017-10-11 00:41:56 +02:00
|
|
|
|
2019-05-14 14:48:42 +02:00
|
|
|
std::atomic<uint32_t> m_refCount = { 0ul };
|
|
|
|
std::atomic<uint32_t> m_refPrivate = { 0ul };
|
2017-10-11 00:41:56 +02:00
|
|
|
|
|
|
|
};
|
2019-06-02 00:14:54 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \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<typename Base>
|
|
|
|
class ComObjectClamp : public ComObject<Base> {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
ULONG STDMETHODCALLTYPE Release() {
|
|
|
|
ULONG refCount = this->m_refCount;
|
|
|
|
if (likely(refCount != 0ul)) {
|
|
|
|
this->m_refCount--;
|
|
|
|
refCount--;
|
|
|
|
|
|
|
|
if (refCount == 0ul)
|
|
|
|
this->ReleasePrivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
return refCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2017-10-11 00:41:56 +02:00
|
|
|
|
2018-04-02 12:04:20 +02:00
|
|
|
template<typename T>
|
|
|
|
inline void InitReturnPtr(T** ptr) {
|
|
|
|
if (ptr != nullptr)
|
|
|
|
*ptr = nullptr;
|
|
|
|
}
|
|
|
|
|
2017-10-11 00:41:56 +02:00
|
|
|
}
|