1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-13 19:29:14 +01:00

[util] Fix COM private data bug when passing NULL interface

Fixes test failure in wine's DXGI tests.
This commit is contained in:
Philip Rebohle 2019-06-11 16:08:28 +02:00
parent 6d999fad89
commit 96b9058fbf
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 36 additions and 18 deletions

View File

@ -12,6 +12,7 @@ namespace dxvk {
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);
@ -22,8 +23,9 @@ namespace dxvk {
REFGUID guid,
const IUnknown* iface)
: m_guid (guid),
m_type(ComPrivateDataType::Iface),
m_iface (const_cast<IUnknown*>(iface)) {
if (m_iface != nullptr)
if (m_iface)
m_iface->AddRef();
}
@ -35,10 +37,12 @@ namespace dxvk {
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;
@ -48,11 +52,13 @@ namespace dxvk {
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;
@ -61,22 +67,24 @@ namespace dxvk {
HRESULT ComPrivateDataEntry::get(UINT& size, void* data) const {
const UINT minSize = m_iface != nullptr
? sizeof(IUnknown*)
: m_size;
UINT minSize = 0;
if (m_type == ComPrivateDataType::Iface) minSize = sizeof(IUnknown*);
if (m_type == ComPrivateDataType::Data) minSize = m_size;
if (data == nullptr) {
if (!data) {
size = minSize;
return S_OK;
}
const HRESULT result = size < minSize
HRESULT result = size < minSize
? DXGI_ERROR_MORE_DATA
: S_OK;
if (size >= minSize) {
if (m_iface != nullptr) {
m_iface->AddRef();
if (m_type == ComPrivateDataType::Iface) {
if (m_iface)
m_iface->AddRef();
std::memcpy(data, &m_iface, minSize);
} else {
std::memcpy(data, m_data, minSize);
@ -89,9 +97,9 @@ namespace dxvk {
void ComPrivateDataEntry::destroy() {
if (m_data != nullptr)
if (m_data)
std::free(m_data);
if (m_iface != nullptr)
if (m_iface)
m_iface->Release();
}
@ -100,7 +108,7 @@ namespace dxvk {
REFGUID guid,
UINT size,
const void* data) {
if (data == nullptr) {
if (!data) {
for (auto it = m_entries.begin(); it != m_entries.end(); ++it) {
if (it->hasGuid(guid)) {
m_entries.erase(it);
@ -126,12 +134,12 @@ namespace dxvk {
REFGUID guid,
UINT* size,
void* data) {
if (size == nullptr)
if (!size)
return E_INVALIDARG;
auto entry = this->findEntry(guid);
if (entry == nullptr) {
if (!entry) {
*size = 0;
return DXGI_ERROR_NOT_FOUND;
}
@ -154,7 +162,7 @@ namespace dxvk {
ComPrivateDataEntry srcEntry = std::move(entry);
ComPrivateDataEntry* dstEntry = this->findEntry(srcEntry.guid());
if (dstEntry != nullptr)
if (dstEntry)
*dstEntry = std::move(srcEntry);
else
m_entries.push_back(std::move(srcEntry));

View File

@ -6,6 +6,15 @@
namespace dxvk {
/**
* \brief COM private data entry type
*/
enum ComPrivateDataType {
None,
Data,
Iface,
};
/**
* \brief Data entry for private storage
* Stores a single private storage item.
@ -58,10 +67,11 @@ namespace dxvk {
private:
GUID m_guid = __uuidof(IUnknown);
UINT m_size = 0;
void* m_data = nullptr;
IUnknown* m_iface = nullptr;
GUID m_guid = __uuidof(IUnknown);
ComPrivateDataType m_type = ComPrivateDataType::None;
UINT m_size = 0;
void* m_data = nullptr;
IUnknown* m_iface = nullptr;
void destroy();