QRhi: fix potential ODR issue (operators for foreign types)

We mustn't define operators or hash functions for types we don't own,
esp. not in a header file, because when someone else gets the same
idea, we have an ODR violation, unless they get it token-for-token the
same as our implementation.

One option would be to replace the QHash with an STL container. Those
can take per-container Hash and Equal function objects, so we wouldn't
need to declare the global ones.

But let's use a wrapper around the type on which we define the missing
operators instead.

As a drive-by, rename the arguments to the idiomatic lhs/rhs/key, from
a/b/s.

Change-Id: Ibbc2083bcd7423c5d443a0ca1b820cbecb241865
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Marc Mutz 2023-02-08 16:23:42 +01:00 committed by Laszlo Agocs
parent 3a3b76e040
commit da8fa2d08e
2 changed files with 42 additions and 15 deletions

View File

@ -2362,14 +2362,14 @@ void QD3D12SamplerManager::destroy()
QD3D12Descriptor QD3D12SamplerManager::getShaderVisibleDescriptor(const D3D12_SAMPLER_DESC &desc)
{
auto it = gpuMap.constFind(desc);
auto it = gpuMap.constFind({desc});
if (it != gpuMap.cend())
return *it;
QD3D12Descriptor descriptor = shaderVisibleSamplerHeap.heap.get(1);
if (descriptor.isValid()) {
device->CreateSampler(&desc, descriptor.cpuHandle);
gpuMap.insert(desc, descriptor);
gpuMap.insert({desc}, descriptor);
} else {
qWarning("Out of shader-visible SAMPLER descriptor heap space,"
" this should not happen, maximum number of unique samplers is %u",

View File

@ -20,6 +20,7 @@
#include "qshaderdescription_p.h"
#include <QWindow>
#include <QBitArray>
#include <optional>
#include <array>
@ -30,11 +31,6 @@
#include "D3D12MemAlloc.h"
inline size_t qHash(const D3D12_SAMPLER_DESC &s, size_t seed = 0) noexcept
{
return QT_PREPEND_NAMESPACE(qHashBits)(&s, sizeof(s), seed);
}
QT_BEGIN_NAMESPACE
static const int QD3D12_FRAMES_IN_FLIGHT = 2;
@ -457,16 +453,47 @@ struct QD3D12ShaderVisibleDescriptorHeap
QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
};
inline bool operator==(const D3D12_SAMPLER_DESC &a, const D3D12_SAMPLER_DESC &b) noexcept
// wrap foreign struct so we can legally supply equality operators and qHash:
struct Q_D3D12_SAMPLER_DESC
{
return !memcmp(&a, &b, sizeof(D3D12_SAMPLER_DESC));
D3D12_SAMPLER_DESC desc;
friend bool operator==(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
{
return lhs.desc.Filter == rhs.desc.Filter
&& lhs.desc.AddressU == rhs.desc.AddressU
&& lhs.desc.AddressV == rhs.desc.AddressV
&& lhs.desc.AddressW == rhs.desc.AddressW
&& lhs.desc.MipLODBias == rhs.desc.MipLODBias
&& lhs.desc.MaxAnisotropy == rhs.desc.MaxAnisotropy
&& lhs.desc.ComparisonFunc == rhs.desc.ComparisonFunc
// BorderColor is never used, skip it
&& lhs.desc.MinLOD == rhs.desc.MinLOD
&& lhs.desc.MaxLOD == rhs.desc.MaxLOD;
}
inline bool operator!=(const D3D12_SAMPLER_DESC &a, const D3D12_SAMPLER_DESC &b) noexcept
friend bool operator!=(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
{
return !(a == b);
return !(lhs == rhs);
}
friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
{
QtPrivate::QHashCombine hash;
seed = hash(seed, key.desc.Filter);
seed = hash(seed, key.desc.AddressU);
seed = hash(seed, key.desc.AddressV);
seed = hash(seed, key.desc.AddressW);
seed = hash(seed, key.desc.MipLODBias);
seed = hash(seed, key.desc.MaxAnisotropy);
seed = hash(seed, key.desc.ComparisonFunc);
// BorderColor is never used, skip it
seed = hash(seed, key.desc.MinLOD);
seed = hash(seed, key.desc.MaxLOD);
return seed;
}
};
struct QD3D12SamplerManager
{
const quint32 MAX_SAMPLERS = 512;
@ -478,7 +505,7 @@ struct QD3D12SamplerManager
ID3D12Device *device = nullptr;
QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
QHash<D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
};
enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };