Commit f6fc566d authored by Laszlo Agocs's avatar Laszlo Agocs

Revise the API for importing existing device objects

parent 2f9c2180
......@@ -64,12 +64,12 @@ void Renderer::initResources()
{
QRhiVulkanInitParams params;
params.inst = m_window->vulkanInstance();
params.importExistingDevice = true;
params.physDev = m_window->physicalDevice();
params.dev = m_window->device();
params.cmdPool = m_window->graphicsCommandPool();
params.gfxQueue = m_window->graphicsQueue();
m_r = QRhi::create(QRhi::Vulkan, &params);
QRhiVulkanNativeHandles importDev;
importDev.physDev = m_window->physicalDevice();
importDev.dev = m_window->device();
importDev.cmdPool = m_window->graphicsCommandPool();
importDev.gfxQueue = m_window->graphicsQueue();
m_r = QRhi::create(QRhi::Vulkan, &params, 0, &importDev);
m_sc = m_r->newSwapChain();
m_sc->setTarget(m_window); // note: very different from setWindow(m_window)
......
......@@ -2529,17 +2529,18 @@ QRhi::~QRhi()
features that are potentially expensive and should only be used during
development.
*/
QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags)
QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice)
{
QScopedPointer<QRhi> r(new QRhi);
switch (impl) {
case Null:
r->d = new QRhiNull(params);
r->d = new QRhiNull(static_cast<QRhiNullInitParams *>(params));
break;
case Vulkan:
#if QT_CONFIG(vulkan)
r->d = new QRhiVulkan(params);
r->d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params),
static_cast<QRhiVulkanNativeHandles *>(importDevice));
break;
#else
qWarning("This build of Qt has no Vulkan support");
......@@ -2547,7 +2548,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags)
#endif
case OpenGLES2:
#ifndef QT_NO_OPENGL
r->d = new QRhiGles2(params);
r->d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params));
break;
#else
qWarning("This build of Qt has no OpenGL support");
......@@ -2555,7 +2556,8 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags)
#endif
case D3D11:
#ifdef Q_OS_WIN
r->d = new QRhiD3D11(params);
r->d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params),
static_cast<QRhiD3D11NativeHandles *>(importDevice));
break;
#else
qWarning("This platform has no Direct3D 11 support");
......@@ -2563,7 +2565,8 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags)
#endif
case Metal:
#ifdef Q_OS_DARWIN
r->d = new QRhiMetal(params);
r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
static_cast<QRhiMetalNativeHandles *>(importDevice));
break;
#else
qWarning("This platform has no Metal support");
......
......@@ -1155,7 +1155,10 @@ public:
~QRhi();
static QRhi *create(Implementation impl, QRhiInitParams *params, Flags flags = Flags());
static QRhi *create(Implementation impl,
QRhiInitParams *params,
Flags flags = Flags(),
QRhiNativeHandles *importDevice = nullptr);
QRhiGraphicsPipeline *newGraphicsPipeline();
QRhiShaderResourceBindings *newShaderResourceBindings();
......
......@@ -78,19 +78,16 @@ QT_BEGIN_NAMESPACE
\section2 Working with existing Direct3D 11 devices
When interoperating with another graphics engine, it may be necessary to
get a QRhi instance that uses the same Direct3D device and device context.
This can be achieved by setting importExistingDevice to \c true and
providing both dev and context.
get a QRhi instance that uses the same Direct3D device. This can be
achieved by passing a pointer to a QRhiD3D11NativeHandles to
QRhi::create(). Both the device and the device context must be set to a
non-null value then.
The QRhi does not take ownership of any of the external objects.
\note QRhi works with immediate contexts only. Deferred contexts are not
used in any way.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual types are
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
\note Regardless of using an imported or a QRhi-created device context, the
\c ID3D11DeviceContext1 interface (Direct3D 11.1) must be supported.
Initialization will fail otherwise.
......@@ -111,28 +108,40 @@ QT_BEGIN_NAMESPACE
\class QRhiD3D11NativeHandles
\inmodule QtRhi
\brief Holds the D3D device and device context used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual types are
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
*/
/*!
\class QRhiD3D11TextureNativeHandles
\inmodule QtRhi
\brief Holds the D3D texture object that is backing a QRhiTexture instance.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual type is
\c{ID3D11Texture2D *}.
*/
QRhiD3D11::QRhiD3D11(QRhiInitParams *params)
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice)
: ofr(this)
{
QRhiD3D11InitParams *d3dparams = static_cast<QRhiD3D11InitParams *>(params);
debugLayer = d3dparams->enableDebugLayer;
importedDevice = d3dparams->importExistingDevice;
debugLayer = params->enableDebugLayer;
importedDevice = importDevice != nullptr;
if (importedDevice) {
dev = reinterpret_cast<ID3D11Device *>(d3dparams->dev);
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(d3dparams->context);
if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
// get rid of the ref added by QueryInterface
ctx->Release();
dev = reinterpret_cast<ID3D11Device *>(importDevice->dev);
if (dev) {
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importDevice->context);
if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
// get rid of the ref added by QueryInterface
ctx->Release();
} else {
qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
importedDevice = false;
}
} else {
qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
qWarning("No ID3D11Device given, cannot import");
importedDevice = false;
}
}
......
......@@ -47,16 +47,12 @@ QT_BEGIN_NAMESPACE
struct Q_RHI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
{
bool enableDebugLayer = false;
bool importExistingDevice = false;
void *dev = nullptr;
void *context = nullptr;
};
struct Q_RHI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
{
void *dev;
void *context;
void *dev = nullptr;
void *context = nullptr;
};
struct Q_RHI_EXPORT QRhiD3D11TextureNativeHandles : public QRhiNativeHandles
......
......@@ -445,7 +445,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
class QRhiD3D11 : public QRhiImplementation
{
public:
QRhiD3D11(QRhiInitParams *params);
QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice = nullptr);
bool create(QRhi::Flags flags) override;
void destroy() override;
......
......@@ -122,13 +122,12 @@ QT_BEGIN_NAMESPACE
\brief Holds the OpenGL texture object that is backing a QRhiTexture instance.
*/
QRhiGles2::QRhiGles2(QRhiInitParams *params)
QRhiGles2::QRhiGles2(QRhiGles2InitParams *params)
: ofr(this)
{
QRhiGles2InitParams *glparams = static_cast<QRhiGles2InitParams *>(params);
ctx = glparams->context;
maybeWindow = glparams->window; // may be null
fallbackSurface = glparams->fallbackSurface;
ctx = params->context;
maybeWindow = params->window; // may be null
fallbackSurface = params->fallbackSurface;
}
bool QRhiGles2::ensureContext(QSurface *surface) const
......
......@@ -440,7 +440,7 @@ struct QGles2SwapChain : public QRhiSwapChain
class QRhiGles2 : public QRhiImplementation
{
public:
QRhiGles2(QRhiInitParams *params);
QRhiGles2(QRhiGles2InitParams *params);
bool create(QRhi::Flags flags) override;
void destroy() override;
......
......@@ -45,14 +45,12 @@ QT_BEGIN_NAMESPACE
struct Q_RHI_EXPORT QRhiMetalInitParams : public QRhiInitParams
{
bool importExistingDevice = false;
void *dev = nullptr;
};
struct Q_RHI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
{
void *dev;
void *cmdQueue;
void *dev = nullptr;
void *cmdQueue = nullptr;
};
struct Q_RHI_EXPORT QRhiMetalTextureNativeHandles : public QRhiNativeHandles
......
......@@ -89,11 +89,9 @@ QT_BEGIN_NAMESPACE
When interoperating with another graphics engine, it may be necessary to
get a QRhi instance that uses the same Metal device. This can be achieved
by setting importExistingDevice to \c true and providing dev.
\note The class uses \c{void *} as the type since including the Objective C
headers is not acceptable here. The actual type is \c{id<MTLDevice>} or
\c{MTLDevice *}.
by passing a pointer to a QRhiMetalNativeHandles to QRhi::create(). The
device must be set to a non-null value then. Optionally, a command queue
object can be specified as well.
The QRhi does not take ownership of any of the external objects.
*/
......@@ -102,20 +100,27 @@ QT_BEGIN_NAMESPACE
\class QRhiMetalNativeHandles
\inmodule QtRhi
\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>}.
*/
/*!
\class QRhiMetalTextureNativeHandles
\inmodule QtRhi
\brief Holds the Metal texture object that is backing a QRhiTexture instance.
\note The class uses \c{void *} as the type since including the Objective C
headers is not acceptable here. The actual type is \c{id<MTLTexture>}.
*/
struct QRhiMetalData
{
QRhiMetalData(QRhiImplementation *rhi) : ofr(rhi) { }
id<MTLDevice> dev;
id<MTLCommandQueue> cmdQueue;
id<MTLDevice> dev = nil;
id<MTLCommandQueue> cmdQueue = nil;
MTLRenderPassDescriptor *createDefaultRenderPass(bool hasDepthStencil,
const QRhiColorClearValue &colorClearValue,
......@@ -264,15 +269,23 @@ struct QMetalSwapChainData
MTLPixelFormat colorFormat;
};
QRhiMetal::QRhiMetal(QRhiInitParams *params)
QRhiMetal::QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice)
{
d = new QRhiMetalData(this);
QRhiMetalInitParams *metalparams = static_cast<QRhiMetalInitParams *>(params);
importedDevice = metalparams->importExistingDevice;
Q_UNUSED(params);
importedDevice = importDevice != nullptr;
if (importedDevice) {
d->dev = (id<MTLDevice>) metalparams->dev;
[d->dev retain];
if (d->dev) {
d->dev = (id<MTLDevice>) importDevice->dev;
importedCmdQueue = importDevice->cmdQueue != nullptr;
if (importedCmdQueue)
d->cmdQueue = (id<MTLCommandQueue>) importDevice->cmdQueue;
} else {
qWarning("No MTLDevice given, cannot import");
importedDevice = false;
}
}
}
......@@ -290,12 +303,17 @@ bool QRhiMetal::create(QRhi::Flags flags)
{
Q_UNUSED(flags);
if (!importedDevice)
if (importedDevice)
[d->dev retain];
else
d->dev = MTLCreateSystemDefaultDevice();
qDebug("Metal device: %s", qPrintable(QString::fromNSString([d->dev name])));
d->cmdQueue = [d->dev newCommandQueue];
if (importedCmdQueue)
[d->cmdQueue retain];
else
d->cmdQueue = [d->dev newCommandQueue];
if (@available(macOS 10.13, iOS 11.0, *)) {
d->captureMgr = [MTLCaptureManager sharedCaptureManager];
......@@ -338,21 +356,17 @@ void QRhiMetal::destroy()
finishActiveReadbacks(true);
if (@available(macOS 10.13, iOS 11.0, *)) {
if (d->captureScope) {
[d->captureScope release];
d->captureScope = nil;
}
[d->captureScope release];
d->captureScope = nil;
}
if (d->cmdQueue) {
[d->cmdQueue release];
[d->cmdQueue release];
if (!importedCmdQueue)
d->cmdQueue = nil;
}
if (d->dev) {
[d->dev release];
[d->dev release];
if (!importedDevice)
d->dev = nil;
}
}
QVector<int> QRhiMetal::supportedSampleCounts() const
......
......@@ -272,7 +272,7 @@ struct QRhiMetalData;
class QRhiMetal : public QRhiImplementation
{
public:
QRhiMetal(QRhiInitParams *params);
QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
~QRhiMetal();
bool create(QRhi::Flags flags) override;
......@@ -356,6 +356,7 @@ public:
int effectiveSampleCount(int sampleCount) const;
bool importedDevice = false;
bool importedCmdQueue = false;
bool inFrame = false;
int currentFrameSlot = 0;
bool inPass = false;
......
......@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
\brief Empty.
*/
QRhiNull::QRhiNull(QRhiInitParams *params)
QRhiNull::QRhiNull(QRhiNullInitParams *params)
{
Q_UNUSED(params);
}
......
......@@ -164,7 +164,7 @@ struct QNullSwapChain : public QRhiSwapChain
class QRhiNull : public QRhiImplementation
{
public:
QRhiNull(QRhiInitParams *params);
QRhiNull(QRhiNullInitParams *params);
bool create(QRhi::Flags flags) override;
void destroy() override;
......
......@@ -128,13 +128,14 @@ QT_BEGIN_NAMESPACE
When interoperating with another graphics engine, it may be necessary to
get a QRhi instance that uses the same Vulkan device. This can be achieved
by setting importExistingDevice to \c true and providing the already
created physical device and device objects. In addition, either the
graphics queue family index or the graphics queue object itself is
required. Prefer the former, whenever possible since deducing the index is
not possible afterwards. Optionally, an existing command pool object can be
specified as well, and, also optionally, vmemAllocator can be used to share
the same
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.
In addition, either the graphics queue family index or the graphics queue
object itself is required. Prefer the former, whenever possible since
deducing the index is not possible afterwards. Optionally, an existing
command pool object can be specified as well, and, also optionally,
vmemAllocator can be used to share the same
\l{https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator}{Vulkan
memory allocator} between two QRhi instances.
......@@ -250,21 +251,32 @@ static inline VmaAllocator toVmaAllocator(QVkAllocator a)
return reinterpret_cast<VmaAllocator>(a);
}
QRhiVulkan::QRhiVulkan(QRhiInitParams *params)
QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importDevice)
: ofr(this)
{
QRhiVulkanInitParams *vkparams = static_cast<QRhiVulkanInitParams *>(params);
inst = vkparams->inst;
importedDevPoolQueue = vkparams->importExistingDevice;
if (importedDevPoolQueue) {
physDev = vkparams->physDev;
dev = vkparams->dev;
gfxQueueFamilyIdx = vkparams->gfxQueueFamilyIdx;
gfxQueue = vkparams->gfxQueue;
cmdPool = vkparams->cmdPool;
allocator = vkparams->vmemAllocator;
inst = params->inst;
maybeWindow = params->window; // may be null
importedDevice = importDevice != nullptr;
if (importedDevice) {
physDev = importDevice->physDev;
dev = importDevice->dev;
if (physDev && dev) {
gfxQueueFamilyIdx = importDevice->gfxQueueFamilyIdx;
gfxQueue = importDevice->gfxQueue;
if (importDevice->cmdPool) {
importedCmdPool = true;
cmdPool = importDevice->cmdPool;
}
if (importDevice->vmemAllocator) {
importedAllocator = true;
allocator = importDevice->vmemAllocator;
}
} else {
qWarning("No (physical) Vulkan device is given, cannot import");
importedDevice = false;
}
}
maybeWindow = vkparams->window; // may be null
}
bool QRhiVulkan::create(QRhi::Flags flags)
......@@ -276,7 +288,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
f = inst->functions();
if (!importedDevPoolQueue) {
if (!importedDevice) {
uint32_t devCount = 0;
f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr);
qDebug("%d physical devices", devCount);
......@@ -386,7 +398,8 @@ bool QRhiVulkan::create(QRhi::Flags flags)
}
df = inst->deviceFunctions(dev);
if (!cmdPool) {
if (!importedCmdPool) {
VkCommandPoolCreateInfo poolInfo;
memset(&poolInfo, 0, sizeof(poolInfo));
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
......@@ -397,6 +410,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
return false;
}
}
if (gfxQueueFamilyIdx != -1 && !gfxQueue)
df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
......@@ -409,7 +423,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
VK_VERSION_MINOR(physDevProperties.driverVersion),
VK_VERSION_PATCH(physDevProperties.driverVersion));
if (!allocator) {
if (!importedAllocator) {
VmaVulkanFunctions afuncs;
afuncs.vkGetPhysicalDeviceProperties = wrap_vkGetPhysicalDeviceProperties;
afuncs.vkGetPhysicalDeviceMemoryProperties = wrap_vkGetPhysicalDeviceMemoryProperties;
......@@ -514,17 +528,20 @@ void QRhiVulkan::destroy()
timestampQueryPool = VK_NULL_HANDLE;
}
if (!importedDevPoolQueue) {
if (!importedAllocator && allocator) {
vmaDestroyAllocator(toVmaAllocator(allocator));
if (cmdPool) {
df->vkDestroyCommandPool(dev, cmdPool, nullptr);
cmdPool = VK_NULL_HANDLE;
}
if (dev) {
df->vkDestroyDevice(dev, nullptr);
inst->resetDeviceFunctions(dev);
dev = VK_NULL_HANDLE;
}
allocator = nullptr;
}
if (!importedCmdPool && cmdPool) {
df->vkDestroyCommandPool(dev, cmdPool, nullptr);
cmdPool = VK_NULL_HANDLE;
}
if (!importedDevice && dev) {
df->vkDestroyDevice(dev, nullptr);
inst->resetDeviceFunctions(dev);
dev = VK_NULL_HANDLE;
}
f = nullptr;
......
......@@ -46,8 +46,10 @@ struct Q_RHI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
{
QVulkanInstance *inst = nullptr;
QWindow *window = nullptr;
};
bool importExistingDevice = false;
struct Q_RHI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
{
VkPhysicalDevice physDev = VK_NULL_HANDLE;
VkDevice dev = VK_NULL_HANDLE;
int gfxQueueFamilyIdx = -1;
......@@ -56,16 +58,6 @@ struct Q_RHI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
void *vmemAllocator = nullptr;
};
struct Q_RHI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
{
VkPhysicalDevice physDev;
VkDevice dev;
int gfxQueueFamilyIdx;
VkQueue gfxQueue;
VkCommandPool cmdPool;
void *vmemAllocator;
};
struct Q_RHI_EXPORT QRhiVulkanTextureNativeHandles : public QRhiNativeHandles
{
VkImage image = VK_NULL_HANDLE;
......
......@@ -344,7 +344,7 @@ struct QVkSwapChain : public QRhiSwapChain
class QRhiVulkan : public QRhiImplementation
{
public:
QRhiVulkan(QRhiInitParams *params);
QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importDevice = nullptr);
bool create(QRhi::Flags flags) override;
void destroy() override;
......@@ -485,13 +485,15 @@ public:
QVulkanInstance *inst = nullptr;
QWindow *maybeWindow = nullptr;
bool importedDevPoolQueue = false;
bool importedDevice = false;
VkPhysicalDevice physDev = VK_NULL_HANDLE;
VkDevice dev = VK_NULL_HANDLE;
bool importedCmdPool = false;
VkCommandPool cmdPool = VK_NULL_HANDLE;
int gfxQueueFamilyIdx = -1;
VkQueue gfxQueue = VK_NULL_HANDLE;
quint32 timestampValidBits = 0;
bool importedAllocator = false;
QVkAllocator allocator = nullptr;
QVulkanFunctions *f = nullptr;
QVulkanDeviceFunctions *df = nullptr;
......
......@@ -46,6 +46,7 @@ dxc for d3d as an alternative to fxc?
hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
revise create() and importing external device objects
revise structs in api
primitive restart
fix independent builds
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment