#include #include #include #include "com_private_data.h" namespace dxvk { ComPrivateDataEntry::ComPrivateDataEntry() { } ComPrivateDataEntry::ComPrivateDataEntry( REFGUID guid, UINT size, const void* data) : m_guid(guid), m_type(ComPrivateDataType::Data), m_size(size), m_data(std::malloc(size)) { std::memcpy(m_data, data, size); } ComPrivateDataEntry::ComPrivateDataEntry( REFGUID guid, const IUnknown* iface) : m_guid (guid), m_type(ComPrivateDataType::Iface), m_iface (const_cast(iface)) { if (m_iface) m_iface->AddRef(); } ComPrivateDataEntry::~ComPrivateDataEntry() { this->destroy(); } ComPrivateDataEntry::ComPrivateDataEntry(ComPrivateDataEntry&& other) : m_guid (other.m_guid), m_type (other.m_type), m_size (other.m_size), m_data (other.m_data), m_iface (other.m_iface) { other.m_guid = __uuidof(IUnknown); other.m_type = ComPrivateDataType::None; other.m_size = 0; other.m_data = nullptr; other.m_iface = nullptr; } ComPrivateDataEntry& ComPrivateDataEntry::operator = (ComPrivateDataEntry&& other) { this->destroy(); this->m_guid = other.m_guid; this->m_type = other.m_type; this->m_size = other.m_size; this->m_data = other.m_data; this->m_iface = other.m_iface; other.m_guid = __uuidof(IUnknown); other.m_type = ComPrivateDataType::None; other.m_size = 0; other.m_data = nullptr; other.m_iface = nullptr; return *this; } HRESULT ComPrivateDataEntry::get(UINT& size, void* data) const { UINT minSize = 0; if (m_type == ComPrivateDataType::Iface) minSize = sizeof(IUnknown*); if (m_type == ComPrivateDataType::Data) minSize = m_size; if (!data) { size = minSize; return S_OK; } HRESULT result = size < minSize ? DXGI_ERROR_MORE_DATA : S_OK; if (size >= minSize) { if (m_type == ComPrivateDataType::Iface) { if (m_iface) m_iface->AddRef(); std::memcpy(data, &m_iface, minSize); } else { std::memcpy(data, m_data, minSize); } } size = minSize; return result; } void ComPrivateDataEntry::destroy() { if (m_data) std::free(m_data); if (m_iface) m_iface->Release(); } HRESULT ComPrivateData::setData( REFGUID guid, UINT size, const void* data) { if (!data) { for (auto it = m_entries.begin(); it != m_entries.end(); ++it) { if (it->hasGuid(guid)) { m_entries.erase(it); return S_OK; } } return S_FALSE; } this->insertEntry(ComPrivateDataEntry(guid, size, data)); return S_OK; } HRESULT ComPrivateData::setInterface( REFGUID guid, const IUnknown* iface) { this->insertEntry(ComPrivateDataEntry(guid, iface)); return S_OK; } HRESULT ComPrivateData::getData( REFGUID guid, UINT* size, void* data) { if (!size) return E_INVALIDARG; auto entry = this->findEntry(guid); if (!entry) { *size = 0; return DXGI_ERROR_NOT_FOUND; } return entry->get(*size, data); } ComPrivateDataEntry* ComPrivateData::findEntry(REFGUID guid) { for (ComPrivateDataEntry& e : m_entries) { if (e.hasGuid(guid)) return &e; } return nullptr; } void ComPrivateData::insertEntry(ComPrivateDataEntry&& entry) { ComPrivateDataEntry srcEntry = std::move(entry); ComPrivateDataEntry* dstEntry = this->findEntry(srcEntry.guid()); if (dstEntry) *dstEntry = std::move(srcEntry); else m_entries.push_back(std::move(srcEntry)); } }