rhi: Enable specifying just an adapter or phys dev
Required by OpenXR. A VkPhysicalDevice or an adapter LUID + feature level pair should be adoptable while leaving the rest (device, queue, etc. setup) to QRhi as normal. Change-Id: Iada0972671b037b4efb03e7831b7c9b8c5f2393d Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
b60f516aca
commit
db61e43c81
@ -84,10 +84,15 @@ QT_BEGIN_NAMESPACE
|
|||||||
When interoperating with another graphics engine, it may be necessary to
|
When interoperating with another graphics engine, it may be necessary to
|
||||||
get a QRhi instance that uses the same Direct3D device. This can be
|
get a QRhi instance that uses the same Direct3D device. This can be
|
||||||
achieved by passing a pointer to a QRhiD3D11NativeHandles to
|
achieved by passing a pointer to a QRhiD3D11NativeHandles to
|
||||||
QRhi::create(). Both the device and the device context must be set to a
|
QRhi::create(). When the device is set to a non-null value, the device
|
||||||
non-null value then.
|
context must be specified as well. QRhi does not take ownership of any of
|
||||||
|
the external objects.
|
||||||
|
|
||||||
The QRhi does not take ownership of any of the external objects.
|
Sometimes, for example when using QRhi in combination with OpenXR, one will
|
||||||
|
want to specify which adapter to use, and optionally, which feature level
|
||||||
|
to request on the device, while leaving the device creation to QRhi. This
|
||||||
|
is achieved by leaving the device and context pointers set to null, while
|
||||||
|
specifying the adapter LUID and feature level.
|
||||||
|
|
||||||
\note QRhi works with immediate contexts only. Deferred contexts are not
|
\note QRhi works with immediate contexts only. Deferred contexts are not
|
||||||
used in any way.
|
used in any way.
|
||||||
@ -117,7 +122,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
#define D3D11_1_UAV_SLOT_COUNT 64
|
#define D3D11_1_UAV_SLOT_COUNT 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice)
|
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importParams)
|
||||||
: ofr(this),
|
: ofr(this),
|
||||||
deviceCurse(this)
|
deviceCurse(this)
|
||||||
{
|
{
|
||||||
@ -126,22 +131,21 @@ QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *import
|
|||||||
deviceCurse.framesToActivate = params->framesUntilKillingDeviceViaTdr;
|
deviceCurse.framesToActivate = params->framesUntilKillingDeviceViaTdr;
|
||||||
deviceCurse.permanent = params->repeatDeviceKill;
|
deviceCurse.permanent = params->repeatDeviceKill;
|
||||||
|
|
||||||
importedDevice = importDevice != nullptr;
|
if (importParams) {
|
||||||
if (importedDevice) {
|
if (importParams->dev && importParams->context) {
|
||||||
dev = reinterpret_cast<ID3D11Device *>(importDevice->dev);
|
dev = reinterpret_cast<ID3D11Device *>(importParams->dev);
|
||||||
if (dev) {
|
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importParams->context);
|
||||||
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importDevice->context);
|
|
||||||
if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
|
if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
|
||||||
// get rid of the ref added by QueryInterface
|
// get rid of the ref added by QueryInterface
|
||||||
ctx->Release();
|
ctx->Release();
|
||||||
|
importedDeviceAndContext = true;
|
||||||
} else {
|
} else {
|
||||||
qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
|
qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
|
||||||
importedDevice = false;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
qWarning("No ID3D11Device given, cannot import");
|
|
||||||
importedDevice = false;
|
|
||||||
}
|
}
|
||||||
|
featureLevel = D3D_FEATURE_LEVEL(importParams->featureLevel);
|
||||||
|
adapterLuid.LowPart = importParams->adapterLuidLow;
|
||||||
|
adapterLuid.HighPart = importParams->adapterLuidHigh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,13 +219,28 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
qCDebug(QRHI_LOG_INFO, "DXGI 1.2 = %s, FLIP_DISCARD swapchain supported = %s",
|
qCDebug(QRHI_LOG_INFO, "DXGI 1.2 = %s, FLIP_DISCARD swapchain supported = %s",
|
||||||
hasDxgi2 ? "true" : "false", supportsFlipDiscardSwapchain ? "true" : "false");
|
hasDxgi2 ? "true" : "false", supportsFlipDiscardSwapchain ? "true" : "false");
|
||||||
|
|
||||||
if (!importedDevice) {
|
if (!importedDeviceAndContext) {
|
||||||
IDXGIAdapter1 *adapterToUse = nullptr;
|
IDXGIAdapter1 *adapterToUse = nullptr;
|
||||||
IDXGIAdapter1 *adapter;
|
IDXGIAdapter1 *adapter;
|
||||||
int requestedAdapterIndex = -1;
|
int requestedAdapterIndex = -1;
|
||||||
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
|
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
|
||||||
requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
|
requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
|
||||||
|
|
||||||
|
// The importParams may specify an adapter by the luid, take that into account.
|
||||||
|
if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
|
||||||
|
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
|
||||||
|
DXGI_ADAPTER_DESC1 desc;
|
||||||
|
adapter->GetDesc1(&desc);
|
||||||
|
adapter->Release();
|
||||||
|
if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
|
||||||
|
&& desc.AdapterLuid.HighPart == adapterLuid.HighPart)
|
||||||
|
{
|
||||||
|
requestedAdapterIndex = adapterIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
|
if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
|
||||||
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
|
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
|
||||||
DXGI_ADAPTER_DESC1 desc;
|
DXGI_ADAPTER_DESC1 desc;
|
||||||
@ -246,6 +265,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
desc.Flags);
|
desc.Flags);
|
||||||
if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
|
if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
|
||||||
adapterToUse = adapter;
|
adapterToUse = adapter;
|
||||||
|
adapterLuid = desc.AdapterLuid;
|
||||||
qCDebug(QRHI_LOG_INFO, " using this adapter");
|
qCDebug(QRHI_LOG_INFO, " using this adapter");
|
||||||
} else {
|
} else {
|
||||||
adapter->Release();
|
adapter->Release();
|
||||||
@ -256,9 +276,20 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normally we won't specify a requested feature level list,
|
||||||
|
// except when a level was specified in importParams.
|
||||||
|
QVarLengthArray<D3D_FEATURE_LEVEL, 4> requestedFeatureLevels;
|
||||||
|
bool requestFeatureLevels = false;
|
||||||
|
if (featureLevel) {
|
||||||
|
requestFeatureLevels = true;
|
||||||
|
requestedFeatureLevels.append(featureLevel);
|
||||||
|
}
|
||||||
|
|
||||||
ID3D11DeviceContext *ctx = nullptr;
|
ID3D11DeviceContext *ctx = nullptr;
|
||||||
HRESULT hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
|
HRESULT hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
|
||||||
nullptr, 0, D3D11_SDK_VERSION,
|
requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
|
||||||
|
requestFeatureLevels ? requestedFeatureLevels.count() : 0,
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
&dev, &featureLevel, &ctx);
|
&dev, &featureLevel, &ctx);
|
||||||
// We cannot assume that D3D11_CREATE_DEVICE_DEBUG is always available. Retry without it, if needed.
|
// We cannot assume that D3D11_CREATE_DEVICE_DEBUG is always available. Retry without it, if needed.
|
||||||
if (hr == DXGI_ERROR_SDK_COMPONENT_MISSING && debugLayer) {
|
if (hr == DXGI_ERROR_SDK_COMPONENT_MISSING && debugLayer) {
|
||||||
@ -266,7 +297,9 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
"Attempting to create D3D11 device without it.");
|
"Attempting to create D3D11 device without it.");
|
||||||
devFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
|
devFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
|
||||||
hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
|
hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
|
||||||
nullptr, 0, D3D11_SDK_VERSION,
|
requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
|
||||||
|
requestFeatureLevels ? requestedFeatureLevels.count() : 0,
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
&dev, &featureLevel, &ctx);
|
&dev, &featureLevel, &ctx);
|
||||||
}
|
}
|
||||||
adapterToUse->Release();
|
adapterToUse->Release();
|
||||||
@ -283,6 +316,18 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
} else {
|
} else {
|
||||||
Q_ASSERT(dev && context);
|
Q_ASSERT(dev && context);
|
||||||
featureLevel = dev->GetFeatureLevel();
|
featureLevel = dev->GetFeatureLevel();
|
||||||
|
IDXGIDevice *dxgiDev = nullptr;
|
||||||
|
if (SUCCEEDED(dev->QueryInterface(IID_IDXGIDevice, reinterpret_cast<void **>(&dxgiDev)))) {
|
||||||
|
IDXGIAdapter *adapter = nullptr;
|
||||||
|
if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
|
||||||
|
DXGI_ADAPTER_DESC desc;
|
||||||
|
adapter->GetDesc(&desc);
|
||||||
|
adapterLuid = desc.AdapterLuid;
|
||||||
|
adapter->Release();
|
||||||
|
}
|
||||||
|
dxgiDev->Release();
|
||||||
|
}
|
||||||
|
qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(context->QueryInterface(IID_ID3DUserDefinedAnnotation, reinterpret_cast<void **>(&annotations))))
|
if (FAILED(context->QueryInterface(IID_ID3DUserDefinedAnnotation, reinterpret_cast<void **>(&annotations))))
|
||||||
@ -292,6 +337,9 @@ bool QRhiD3D11::create(QRhi::Flags flags)
|
|||||||
|
|
||||||
nativeHandlesStruct.dev = dev;
|
nativeHandlesStruct.dev = dev;
|
||||||
nativeHandlesStruct.context = context;
|
nativeHandlesStruct.context = context;
|
||||||
|
nativeHandlesStruct.featureLevel = featureLevel;
|
||||||
|
nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
|
||||||
|
nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
|
||||||
|
|
||||||
if (deviceCurse.framesToActivate > 0)
|
if (deviceCurse.framesToActivate > 0)
|
||||||
deviceCurse.initResources();
|
deviceCurse.initResources();
|
||||||
@ -320,7 +368,7 @@ void QRhiD3D11::destroy()
|
|||||||
annotations = nullptr;
|
annotations = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!importedDevice) {
|
if (!importedDeviceAndContext) {
|
||||||
if (context) {
|
if (context) {
|
||||||
context->Release();
|
context->Release();
|
||||||
context = nullptr;
|
context = nullptr;
|
||||||
|
@ -50,8 +50,7 @@
|
|||||||
|
|
||||||
#include <private/qrhi_p.h>
|
#include <private/qrhi_p.h>
|
||||||
|
|
||||||
// no d3d includes here, to prevent precompiled header mess (due to this being
|
// no d3d includes here, to prevent precompiled header mess due to COM
|
||||||
// a public header)
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -65,8 +64,13 @@ struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
|
|||||||
|
|
||||||
struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
|
struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
|
||||||
{
|
{
|
||||||
|
// to import a device and a context
|
||||||
void *dev = nullptr;
|
void *dev = nullptr;
|
||||||
void *context = nullptr;
|
void *context = nullptr;
|
||||||
|
// alternatively, to specify the device feature level and/or the adapter to use
|
||||||
|
int featureLevel = 0;
|
||||||
|
quint32 adapterLuidLow = 0;
|
||||||
|
qint32 adapterLuidHigh = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -670,10 +670,11 @@ public:
|
|||||||
void clearShaderCache();
|
void clearShaderCache();
|
||||||
|
|
||||||
bool debugLayer = false;
|
bool debugLayer = false;
|
||||||
bool importedDevice = false;
|
bool importedDeviceAndContext = false;
|
||||||
ID3D11Device *dev = nullptr;
|
ID3D11Device *dev = nullptr;
|
||||||
ID3D11DeviceContext1 *context = nullptr;
|
ID3D11DeviceContext1 *context = nullptr;
|
||||||
D3D_FEATURE_LEVEL featureLevel;
|
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL(0);
|
||||||
|
LUID adapterLuid = {};
|
||||||
ID3DUserDefinedAnnotation *annotations = nullptr;
|
ID3DUserDefinedAnnotation *annotations = nullptr;
|
||||||
IDXGIFactory1 *dxgiFactory = nullptr;
|
IDXGIFactory1 *dxgiFactory = nullptr;
|
||||||
bool hasDxgi2 = false;
|
bool hasDxgi2 = false;
|
||||||
|
@ -107,10 +107,6 @@ QT_BEGIN_NAMESPACE
|
|||||||
\class QRhiMetalNativeHandles
|
\class QRhiMetalNativeHandles
|
||||||
\inmodule QtRhi
|
\inmodule QtRhi
|
||||||
\brief Holds the Metal device used by the QRhi.
|
\brief Holds the Metal device used by the QRhi.
|
||||||
|
|
||||||
\note The class uses \c{void *} as the type since including the Objective C
|
|
||||||
headers is not acceptable here. The actual types are \c{id<MTLDevice>} and
|
|
||||||
\c{id<MTLCommandQueue>}.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -413,8 +409,8 @@ bool QRhiMetal::create(QRhi::Flags flags)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nativeHandlesStruct.dev = d->dev;
|
nativeHandlesStruct.dev = (MTLDevice *) d->dev;
|
||||||
nativeHandlesStruct.cmdQueue = d->cmdQueue;
|
nativeHandlesStruct.cmdQueue = (MTLCommandQueue *) d->cmdQueue;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -3657,8 +3653,8 @@ void QMetalCommandBuffer::destroy()
|
|||||||
|
|
||||||
const QRhiNativeHandles *QMetalCommandBuffer::nativeHandles()
|
const QRhiNativeHandles *QMetalCommandBuffer::nativeHandles()
|
||||||
{
|
{
|
||||||
nativeHandlesStruct.commandBuffer = d->cb;
|
nativeHandlesStruct.commandBuffer = (MTLCommandBuffer *) d->cb;
|
||||||
nativeHandlesStruct.encoder = d->currentRenderPassEncoder;
|
nativeHandlesStruct.encoder = (MTLRenderCommandEncoder *) d->currentRenderPassEncoder;
|
||||||
return &nativeHandlesStruct;
|
return &nativeHandlesStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,10 @@
|
|||||||
|
|
||||||
#include <private/qrhi_p.h>
|
#include <private/qrhi_p.h>
|
||||||
|
|
||||||
// no Metal includes here, the user code may be plain C++
|
Q_FORWARD_DECLARE_OBJC_CLASS(MTLDevice);
|
||||||
|
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandQueue);
|
||||||
|
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandBuffer);
|
||||||
|
Q_FORWARD_DECLARE_OBJC_CLASS(MTLRenderCommandEncoder);
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -60,14 +63,14 @@ struct Q_GUI_EXPORT QRhiMetalInitParams : public QRhiInitParams
|
|||||||
|
|
||||||
struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
|
struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
|
||||||
{
|
{
|
||||||
void *dev = nullptr; // id<MTLDevice>
|
MTLDevice *dev = nullptr;
|
||||||
void *cmdQueue = nullptr; // id<MTLCommandQueue>
|
MTLCommandQueue *cmdQueue = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
|
struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
|
||||||
{
|
{
|
||||||
void *commandBuffer = nullptr; // id<MTLCommandBuffer>
|
MTLCommandBuffer *commandBuffer = nullptr;
|
||||||
void *encoder = nullptr; // id<MTLRenderCommandEncoder>
|
MTLRenderCommandEncoder *encoder = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -159,12 +159,19 @@ QT_BEGIN_NAMESPACE
|
|||||||
get a QRhi instance that uses the same Vulkan device. This can be achieved
|
get a QRhi instance that uses the same Vulkan device. This can be achieved
|
||||||
by passing a pointer to a QRhiVulkanNativeHandles to QRhi::create().
|
by passing a pointer to a QRhiVulkanNativeHandles to QRhi::create().
|
||||||
|
|
||||||
The physical device and device object must then be set to a non-null value.
|
The physical device must always be set to a non-null value. If the
|
||||||
In addition, either the graphics queue family index or the graphics queue
|
intention is to just specify a physical device, but leave the rest of the
|
||||||
object itself is required. Prefer the former, whenever possible since
|
VkDevice and queue creation to QRhi, then no other members need to be
|
||||||
deducing the index is not possible afterwards. Optionally, an existing
|
filled out in the struct. For example, this is the case when working with
|
||||||
command pool object can be specified as well, and, also optionally,
|
OpenXR.
|
||||||
vmemAllocator can be used to share the same
|
|
||||||
|
To adopt an existing \c VkDevice, the device field must be set to a
|
||||||
|
non-null value as well. In addition, the graphics queue family index is
|
||||||
|
required. The queue index is optional, as the default of 0 is often
|
||||||
|
suitable.
|
||||||
|
|
||||||
|
Optionally, an existing command pool object can be specified as well. Also
|
||||||
|
optionally, vmemAllocator can be used to share the same
|
||||||
\l{https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator}{Vulkan
|
\l{https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator}{Vulkan
|
||||||
memory allocator} between two QRhi instances.
|
memory allocator} between two QRhi instances.
|
||||||
|
|
||||||
@ -298,31 +305,29 @@ static inline VmaAllocator toVmaAllocator(QVkAllocator a)
|
|||||||
return reinterpret_cast<VmaAllocator>(a);
|
return reinterpret_cast<VmaAllocator>(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importDevice)
|
QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams)
|
||||||
: ofr(this)
|
: ofr(this)
|
||||||
{
|
{
|
||||||
inst = params->inst;
|
inst = params->inst;
|
||||||
maybeWindow = params->window; // may be null
|
maybeWindow = params->window; // may be null
|
||||||
requestedDeviceExtensions = params->deviceExtensions;
|
requestedDeviceExtensions = params->deviceExtensions;
|
||||||
|
|
||||||
importedDevice = importDevice != nullptr;
|
if (importParams) {
|
||||||
if (importedDevice) {
|
physDev = importParams->physDev;
|
||||||
physDev = importDevice->physDev;
|
dev = importParams->dev;
|
||||||
dev = importDevice->dev;
|
if (dev && physDev) {
|
||||||
if (physDev && dev) {
|
importedDevice = true;
|
||||||
gfxQueueFamilyIdx = importDevice->gfxQueueFamilyIdx;
|
gfxQueueFamilyIdx = importParams->gfxQueueFamilyIdx;
|
||||||
gfxQueue = importDevice->gfxQueue;
|
gfxQueueIdx = importParams->gfxQueueIdx;
|
||||||
if (importDevice->cmdPool) {
|
// gfxQueue is output only, no point in accepting it as input
|
||||||
|
if (importParams->cmdPool) {
|
||||||
importedCmdPool = true;
|
importedCmdPool = true;
|
||||||
cmdPool = importDevice->cmdPool;
|
cmdPool = importParams->cmdPool;
|
||||||
}
|
}
|
||||||
if (importDevice->vmemAllocator) {
|
if (importParams->vmemAllocator) {
|
||||||
importedAllocator = true;
|
importedAllocator = true;
|
||||||
allocator = importDevice->vmemAllocator;
|
allocator = importParams->vmemAllocator;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
qWarning("No (physical) Vulkan device is given, cannot import");
|
|
||||||
importedDevice = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +384,8 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
|
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!importedDevice) {
|
// Choose a physical device, unless one was provided in importParams.
|
||||||
|
if (!physDev) {
|
||||||
uint32_t physDevCount = 0;
|
uint32_t physDevCount = 0;
|
||||||
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, nullptr);
|
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &physDevCount, nullptr);
|
||||||
if (!physDevCount) {
|
if (!physDevCount) {
|
||||||
@ -433,16 +439,29 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
physDev = physDevs[physDevIndex];
|
physDev = physDevs[physDevIndex];
|
||||||
|
} else {
|
||||||
|
f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
|
||||||
|
qCDebug(QRHI_LOG_INFO, "Using imported physical device '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
|
||||||
|
physDevProperties.deviceName,
|
||||||
|
VK_VERSION_MAJOR(physDevProperties.driverVersion),
|
||||||
|
VK_VERSION_MINOR(physDevProperties.driverVersion),
|
||||||
|
VK_VERSION_PATCH(physDevProperties.driverVersion),
|
||||||
|
VK_VERSION_MAJOR(physDevProperties.apiVersion),
|
||||||
|
VK_VERSION_MINOR(physDevProperties.apiVersion),
|
||||||
|
VK_VERSION_PATCH(physDevProperties.apiVersion),
|
||||||
|
physDevProperties.vendorID,
|
||||||
|
physDevProperties.deviceID,
|
||||||
|
physDevProperties.deviceType);
|
||||||
|
}
|
||||||
|
|
||||||
queryQueueFamilyProps();
|
// Choose queue and create device, unless the device was specified in importParams.
|
||||||
|
if (!importedDevice) {
|
||||||
gfxQueue = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
// We only support combined graphics+present queues. When it comes to
|
// We only support combined graphics+present queues. When it comes to
|
||||||
// compute, only combined graphics+compute queue is used, compute gets
|
// compute, only combined graphics+compute queue is used, compute gets
|
||||||
// disabled otherwise.
|
// disabled otherwise.
|
||||||
gfxQueueFamilyIdx = -1;
|
gfxQueueFamilyIdx = -1;
|
||||||
int computelessGfxQueueCandidateIdx = -1;
|
int computelessGfxQueueCandidateIdx = -1;
|
||||||
|
queryQueueFamilyProps();
|
||||||
for (int i = 0; i < queueFamilyProps.count(); ++i) {
|
for (int i = 0; i < queueFamilyProps.count(); ++i) {
|
||||||
qCDebug(QRHI_LOG_INFO, "queue family %d: flags=0x%x count=%d",
|
qCDebug(QRHI_LOG_INFO, "queue family %d: flags=0x%x count=%d",
|
||||||
i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
|
i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
|
||||||
@ -540,11 +559,13 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
devInfo.enabledExtensionCount = uint32_t(requestedDevExts.count());
|
devInfo.enabledExtensionCount = uint32_t(requestedDevExts.count());
|
||||||
devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
|
devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
|
||||||
|
|
||||||
err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
|
VkResult err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
|
||||||
if (err != VK_SUCCESS) {
|
if (err != VK_SUCCESS) {
|
||||||
qWarning("Failed to create device: %d", err);
|
qWarning("Failed to create device: %d", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
df = inst->deviceFunctions(dev);
|
df = inst->deviceFunctions(dev);
|
||||||
@ -561,16 +582,19 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfxQueueFamilyIdx != -1) {
|
if (gfxQueueFamilyIdx < 0) {
|
||||||
if (!gfxQueue)
|
// this is when importParams is faulty and did not specify the queue family index
|
||||||
df->vkGetDeviceQueue(dev, uint32_t(gfxQueueFamilyIdx), 0, &gfxQueue);
|
qWarning("No queue family index provided");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
df->vkGetDeviceQueue(dev, uint32_t(gfxQueueFamilyIdx), gfxQueueIdx, &gfxQueue);
|
||||||
|
|
||||||
if (queueFamilyProps.isEmpty())
|
if (queueFamilyProps.isEmpty())
|
||||||
queryQueueFamilyProps();
|
queryQueueFamilyProps();
|
||||||
|
|
||||||
hasCompute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
|
hasCompute = (queueFamilyProps[gfxQueueFamilyIdx].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
|
||||||
timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
|
timestampValidBits = queueFamilyProps[gfxQueueFamilyIdx].timestampValidBits;
|
||||||
}
|
|
||||||
|
|
||||||
f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
|
f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
|
||||||
ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
|
ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
|
||||||
@ -651,6 +675,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
nativeHandlesStruct.physDev = physDev;
|
nativeHandlesStruct.physDev = physDev;
|
||||||
nativeHandlesStruct.dev = dev;
|
nativeHandlesStruct.dev = dev;
|
||||||
nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
|
nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
|
||||||
|
nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
|
||||||
nativeHandlesStruct.gfxQueue = gfxQueue;
|
nativeHandlesStruct.gfxQueue = gfxQueue;
|
||||||
nativeHandlesStruct.cmdPool = cmdPool;
|
nativeHandlesStruct.cmdPool = cmdPool;
|
||||||
nativeHandlesStruct.vmemAllocator = allocator;
|
nativeHandlesStruct.vmemAllocator = allocator;
|
||||||
|
@ -62,10 +62,14 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
|
|||||||
|
|
||||||
struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
|
struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
|
||||||
{
|
{
|
||||||
|
// to import a physical device (always required)
|
||||||
VkPhysicalDevice physDev = VK_NULL_HANDLE;
|
VkPhysicalDevice physDev = VK_NULL_HANDLE;
|
||||||
|
// to import a device and queue
|
||||||
VkDevice dev = VK_NULL_HANDLE;
|
VkDevice dev = VK_NULL_HANDLE;
|
||||||
int gfxQueueFamilyIdx = -1;
|
int gfxQueueFamilyIdx = -1;
|
||||||
|
int gfxQueueIdx = 0;
|
||||||
VkQueue gfxQueue = VK_NULL_HANDLE;
|
VkQueue gfxQueue = VK_NULL_HANDLE;
|
||||||
|
// and optionally, command pool and/or mem allocator
|
||||||
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
||||||
void *vmemAllocator = nullptr;
|
void *vmemAllocator = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -645,7 +645,7 @@ struct QVkSwapChain : public QRhiSwapChain
|
|||||||
class QRhiVulkan : public QRhiImplementation
|
class QRhiVulkan : public QRhiImplementation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importDevice = nullptr);
|
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams = nullptr);
|
||||||
|
|
||||||
bool create(QRhi::Flags flags) override;
|
bool create(QRhi::Flags flags) override;
|
||||||
void destroy() override;
|
void destroy() override;
|
||||||
@ -824,6 +824,7 @@ public:
|
|||||||
bool importedCmdPool = false;
|
bool importedCmdPool = false;
|
||||||
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
||||||
int gfxQueueFamilyIdx = -1;
|
int gfxQueueFamilyIdx = -1;
|
||||||
|
int gfxQueueIdx = 0;
|
||||||
VkQueue gfxQueue = VK_NULL_HANDLE;
|
VkQueue gfxQueue = VK_NULL_HANDLE;
|
||||||
bool hasCompute = false;
|
bool hasCompute = false;
|
||||||
quint32 timestampValidBits = 0;
|
quint32 timestampValidBits = 0;
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
#if QT_CONFIG(vulkan)
|
#if QT_CONFIG(vulkan)
|
||||||
# include <QVulkanInstance>
|
# include <QVulkanInstance>
|
||||||
|
# include <QVulkanFunctions>
|
||||||
# include <QtGui/private/qrhivulkan_p.h>
|
# include <QtGui/private/qrhivulkan_p.h>
|
||||||
# define TST_VK
|
# define TST_VK
|
||||||
#endif
|
#endif
|
||||||
@ -73,6 +74,9 @@ private slots:
|
|||||||
void create();
|
void create();
|
||||||
void nativeHandles_data();
|
void nativeHandles_data();
|
||||||
void nativeHandles();
|
void nativeHandles();
|
||||||
|
void nativeHandlesImportVulkan();
|
||||||
|
void nativeHandlesImportD3D11();
|
||||||
|
void nativeHandlesImportOpenGL();
|
||||||
void nativeTexture_data();
|
void nativeTexture_data();
|
||||||
void nativeTexture();
|
void nativeTexture();
|
||||||
void nativeBuffer_data();
|
void nativeBuffer_data();
|
||||||
@ -353,6 +357,7 @@ void tst_QRhi::nativeHandles()
|
|||||||
QVERIFY(vkHandles->physDev);
|
QVERIFY(vkHandles->physDev);
|
||||||
QVERIFY(vkHandles->dev);
|
QVERIFY(vkHandles->dev);
|
||||||
QVERIFY(vkHandles->gfxQueueFamilyIdx >= 0);
|
QVERIFY(vkHandles->gfxQueueFamilyIdx >= 0);
|
||||||
|
QVERIFY(vkHandles->gfxQueueIdx >= 0);
|
||||||
QVERIFY(vkHandles->gfxQueue);
|
QVERIFY(vkHandles->gfxQueue);
|
||||||
QVERIFY(vkHandles->cmdPool);
|
QVERIFY(vkHandles->cmdPool);
|
||||||
QVERIFY(vkHandles->vmemAllocator);
|
QVERIFY(vkHandles->vmemAllocator);
|
||||||
@ -378,6 +383,8 @@ void tst_QRhi::nativeHandles()
|
|||||||
const QRhiD3D11NativeHandles *d3dHandles = static_cast<const QRhiD3D11NativeHandles *>(rhiHandles);
|
const QRhiD3D11NativeHandles *d3dHandles = static_cast<const QRhiD3D11NativeHandles *>(rhiHandles);
|
||||||
QVERIFY(d3dHandles->dev);
|
QVERIFY(d3dHandles->dev);
|
||||||
QVERIFY(d3dHandles->context);
|
QVERIFY(d3dHandles->context);
|
||||||
|
QVERIFY(d3dHandles->featureLevel > 0);
|
||||||
|
QVERIFY(d3dHandles->adapterLuidLow || d3dHandles->adapterLuidHigh);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -494,6 +501,130 @@ void tst_QRhi::nativeHandles()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::nativeHandlesImportVulkan()
|
||||||
|
{
|
||||||
|
#ifdef TST_VK
|
||||||
|
// VkDevice and everything else. For simplicity we'll get QRhi to create one, and then use that with another QRhi.
|
||||||
|
{
|
||||||
|
QScopedPointer<QRhi> rhi(QRhi::create(QRhi::Vulkan, &initParams.vk, QRhi::Flags(), nullptr));
|
||||||
|
if (!rhi)
|
||||||
|
QSKIP("Skipping native Vulkan test");
|
||||||
|
|
||||||
|
const QRhiVulkanNativeHandles *nativeHandles = static_cast<const QRhiVulkanNativeHandles *>(rhi->nativeHandles());
|
||||||
|
QRhiVulkanNativeHandles h = *nativeHandles;
|
||||||
|
// do not pass the rarely used fields, this is useful to test if it creates its own as expected
|
||||||
|
h.cmdPool = VK_NULL_HANDLE;
|
||||||
|
h.vmemAllocator = nullptr;
|
||||||
|
|
||||||
|
QScopedPointer<QRhi> adoptingRhi(QRhi::create(QRhi::Vulkan, &initParams.vk, QRhi::Flags(), &h));
|
||||||
|
QVERIFY(adoptingRhi);
|
||||||
|
|
||||||
|
const QRhiVulkanNativeHandles *newNativeHandles = static_cast<const QRhiVulkanNativeHandles *>(adoptingRhi->nativeHandles());
|
||||||
|
QCOMPARE(newNativeHandles->physDev, nativeHandles->physDev);
|
||||||
|
QCOMPARE(newNativeHandles->dev, nativeHandles->dev);
|
||||||
|
QCOMPARE(newNativeHandles->gfxQueueFamilyIdx, nativeHandles->gfxQueueFamilyIdx);
|
||||||
|
QCOMPARE(newNativeHandles->gfxQueueIdx, nativeHandles->gfxQueueIdx);
|
||||||
|
QVERIFY(newNativeHandles->cmdPool != nativeHandles->cmdPool);
|
||||||
|
QVERIFY(newNativeHandles->vmemAllocator != nativeHandles->vmemAllocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical device only
|
||||||
|
{
|
||||||
|
uint32_t physDevCount = 0;
|
||||||
|
QVulkanFunctions *f = vulkanInstance.functions();
|
||||||
|
f->vkEnumeratePhysicalDevices(vulkanInstance.vkInstance(), &physDevCount, nullptr);
|
||||||
|
if (physDevCount < 1)
|
||||||
|
QSKIP("No Vulkan physical devices, skip");
|
||||||
|
QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount);
|
||||||
|
f->vkEnumeratePhysicalDevices(vulkanInstance.vkInstance(), &physDevCount, physDevs.data());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < physDevCount; ++i) {
|
||||||
|
QRhiVulkanNativeHandles h;
|
||||||
|
h.physDev = physDevs[i];
|
||||||
|
QScopedPointer<QRhi> rhi(QRhi::create(QRhi::Vulkan, &initParams.vk, QRhi::Flags(), &h));
|
||||||
|
// ok if fails, what we want to know is that if it succeeds, it must use that given phys.dev.
|
||||||
|
if (!rhi) {
|
||||||
|
qWarning("Skipping native Vulkan handle test for physical device %u", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const QRhiVulkanNativeHandles *actualNativeHandles = static_cast<const QRhiVulkanNativeHandles *>(rhi->nativeHandles());
|
||||||
|
QCOMPARE(actualNativeHandles->physDev, physDevs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
QSKIP("Skipping Vulkan-specific test");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::nativeHandlesImportD3D11()
|
||||||
|
{
|
||||||
|
#ifdef TST_D3D11
|
||||||
|
QScopedPointer<QRhi> rhi(QRhi::create(QRhi::D3D11, &initParams.d3d, QRhi::Flags(), nullptr));
|
||||||
|
if (!rhi)
|
||||||
|
QSKIP("QRhi could not be created, skipping testing D3D11 native handle import");
|
||||||
|
|
||||||
|
const QRhiD3D11NativeHandles *nativeHandles = static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles());
|
||||||
|
|
||||||
|
// Case 1: device and context
|
||||||
|
{
|
||||||
|
QRhiD3D11NativeHandles h = *nativeHandles;
|
||||||
|
h.featureLevel = 0; // see if these are queried as expected, even when not provided
|
||||||
|
h.adapterLuidLow = 0;
|
||||||
|
h.adapterLuidHigh = 0;
|
||||||
|
QScopedPointer<QRhi> adoptingRhi(QRhi::create(QRhi::D3D11, &initParams.d3d, QRhi::Flags(), &h));
|
||||||
|
QVERIFY(adoptingRhi);
|
||||||
|
const QRhiD3D11NativeHandles *newNativeHandles = static_cast<const QRhiD3D11NativeHandles *>(adoptingRhi->nativeHandles());
|
||||||
|
QCOMPARE(newNativeHandles->dev, nativeHandles->dev);
|
||||||
|
QCOMPARE(newNativeHandles->context, nativeHandles->context);
|
||||||
|
QCOMPARE(newNativeHandles->featureLevel, nativeHandles->featureLevel);
|
||||||
|
QCOMPARE(newNativeHandles->adapterLuidLow, nativeHandles->adapterLuidLow);
|
||||||
|
QCOMPARE(newNativeHandles->adapterLuidHigh, nativeHandles->adapterLuidHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: adapter and feature level only (hello OpenXR)
|
||||||
|
{
|
||||||
|
QRhiD3D11NativeHandles h = *nativeHandles;
|
||||||
|
h.dev = nullptr;
|
||||||
|
h.context = nullptr;
|
||||||
|
QScopedPointer<QRhi> adoptingRhi(QRhi::create(QRhi::D3D11, &initParams.d3d, QRhi::Flags(), &h));
|
||||||
|
QVERIFY(adoptingRhi);
|
||||||
|
const QRhiD3D11NativeHandles *newNativeHandles = static_cast<const QRhiD3D11NativeHandles *>(adoptingRhi->nativeHandles());
|
||||||
|
QVERIFY(newNativeHandles->dev != nativeHandles->dev);
|
||||||
|
QVERIFY(newNativeHandles->context != nativeHandles->context);
|
||||||
|
QCOMPARE(newNativeHandles->featureLevel, nativeHandles->featureLevel);
|
||||||
|
QCOMPARE(newNativeHandles->adapterLuidLow, nativeHandles->adapterLuidLow);
|
||||||
|
QCOMPARE(newNativeHandles->adapterLuidHigh, nativeHandles->adapterLuidHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
QSKIP("Skipping D3D11-specific test");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::nativeHandlesImportOpenGL()
|
||||||
|
{
|
||||||
|
#ifdef TST_GL
|
||||||
|
QRhiGles2NativeHandles h;
|
||||||
|
QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);
|
||||||
|
ctx->setFormat(QRhiGles2InitParams::adjustedFormat());
|
||||||
|
if (!ctx->create())
|
||||||
|
QSKIP("No OpenGL context, skipping OpenGL-specific test");
|
||||||
|
h.context = ctx.data();
|
||||||
|
QScopedPointer<QRhi> rhi(QRhi::create(QRhi::OpenGLES2, &initParams.gl, QRhi::Flags(), &h));
|
||||||
|
if (!rhi)
|
||||||
|
QSKIP("QRhi could not be created, skipping testing OpenGL native handle import");
|
||||||
|
|
||||||
|
const QRhiGles2NativeHandles *actualNativeHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
|
||||||
|
QCOMPARE(actualNativeHandles->context, ctx.data());
|
||||||
|
|
||||||
|
rhi->makeThreadLocalNativeContextCurrent();
|
||||||
|
QCOMPARE(QOpenGLContext::currentContext(), ctx.data());
|
||||||
|
#else
|
||||||
|
QSKIP("Skipping OpenGL-specific test");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QRhi::nativeTexture_data()
|
void tst_QRhi::nativeTexture_data()
|
||||||
{
|
{
|
||||||
rhiTestData();
|
rhiTestData();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user