diff --git a/src/util/com/com_guid.cpp b/src/util/com/com_guid.cpp new file mode 100644 index 00000000..2b81f756 --- /dev/null +++ b/src/util/com/com_guid.cpp @@ -0,0 +1,25 @@ +#include "com_guid.h" + +std::ostream& operator << (std::ostream& os, REFIID guid) { + os.width(8); + os << std::hex << guid.Data1 << '-'; + + os.width(4); + os << std::hex << guid.Data2 << '-'; + + os.width(4); + os << std::hex << guid.Data3 << '-'; + + os.width(2); + os << std::hex + << static_cast(guid.Data4[0]) + << static_cast(guid.Data4[1]) + << '-' + << static_cast(guid.Data4[2]) + << static_cast(guid.Data4[3]) + << static_cast(guid.Data4[4]) + << static_cast(guid.Data4[5]) + << static_cast(guid.Data4[6]) + << static_cast(guid.Data4[7]); + return os; +} diff --git a/src/util/com/com_guid.h b/src/util/com/com_guid.h new file mode 100644 index 00000000..7f34d8b2 --- /dev/null +++ b/src/util/com/com_guid.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "com_include.h" + +std::ostream& operator << (std::ostream& os, REFIID guid); diff --git a/src/util/com/com_include.h b/src/util/com/com_include.h new file mode 100644 index 00000000..f18a98b0 --- /dev/null +++ b/src/util/com/com_include.h @@ -0,0 +1,8 @@ +#pragma once + +// GCC complains about the COM interfaces +// not having virtual destructors +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +#define WIN32_LEAN_AND_MEAN +#include diff --git a/src/util/com/com_object.h b/src/util/com/com_object.h new file mode 100644 index 00000000..4b6b7d1d --- /dev/null +++ b/src/util/com/com_object.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "com_include.h" + +#define COM_QUERY_IFACE(riid, ppvObject, Iface) \ + if (riid == __uuidof(Iface)) { \ + this->AddRef(); \ + *ppvObject = static_cast(this); \ + return S_OK; \ + } + +namespace dxvk { + + template + class ComObject : public Base... { + + public: + + virtual ~ComObject() { } + + ULONG AddRef() final { + return ++m_refCount; + } + + ULONG Release() final { + ULONG refCount = --m_refCount; + if (refCount == 0) + delete this; + return refCount; + } + + private: + + std::atomic m_refCount = { 0ul }; + + }; + +} diff --git a/src/util/com/com_pointer.h b/src/util/com/com_pointer.h new file mode 100644 index 00000000..2fb8242a --- /dev/null +++ b/src/util/com/com_pointer.h @@ -0,0 +1,101 @@ +#pragma once + +#include "com_include.h" + +namespace dxvk { + + /** + * \brief COM pointer + * + * Implements automatic reference + * counting for COM objects. + */ + template + class Com { + + public: + + Com() { } + Com(std::nullptr_t) { } + Com(T* object) + : m_ptr(object) { + this->incRef(); + } + + Com(const Com& other) + : m_ptr(other.m_ptr) { + this->incRef(); + } + + Com(Com&& other) + : m_ptr(other.m_ptr) { + other.m_ptr = nullptr; + } + + Com& operator = (const Com& other) { + other.incRef(); + this->decRef(); + m_ptr = other.m_ptr; + return *this; + } + + Com& operator = (Com&& other) { + this->decRef(); + this->m_ptr = other.m_ptr; + other.m_ptr = nullptr; + return *this; + } + + Com& operator = (std::nullptr_t) { + this->decRef(); + m_ptr = nullptr; + return *this; + } + + ~Com() { + this->decRef(); + } + + T* operator -> () const { + return m_ptr; + } + + T** operator & () { return &m_ptr; } + T* const* operator & () const { return &m_ptr; } + + bool operator == (std::nullptr_t) const { return m_ptr == nullptr; } + bool operator != (std::nullptr_t) const { return m_ptr != nullptr; } + + T* ref() const { + this->incRef(); + return m_ptr; + } + + T* ptr() const { + return m_ptr; + } + + private: + + T* m_ptr = nullptr; + + void incRef() const { + if (m_ptr != nullptr) + m_ptr->AddRef(); + } + + void decRef() const { + if (m_ptr != nullptr) + m_ptr->Release(); + } + + }; + + template + T* ref(T* object) { + if (object != nullptr) + object->AddRef(); + return object; + } + +} diff --git a/src/util/meson.build b/src/util/meson.build index 58cf74a3..05e0cd7d 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -1,4 +1,6 @@ util_src = files([ + 'com/com_guid.cpp', + 'log/log.cpp', 'log/log_debug.cpp', ])