Commit abcdc673 authored by Laszlo Agocs's avatar Laszlo Agocs

Introduce QRhi::nativeHandles() and texture import/export

Implement texture stuff for Metal for now, and exercise
it in texuploads.
parent 40d96904
......@@ -248,7 +248,6 @@ bool QRhiImgui::prepareFrame(QRhiRenderTarget *rt, QRhiRenderPassDescriptor *rp,
void QRhiImgui::queueFrame(QRhiCommandBuffer *cb)
{
ImGuiIO &io(ImGui::GetIO());
ImDrawData *draw = ImGui::GetDrawData();
cb->setViewport({ 0, 0, float(d->lastOutputSize.width()), float(d->lastOutputSize.height()) });
......
......@@ -59,25 +59,30 @@ struct {
QRhiSampler *sampler = nullptr;
QRhiShaderResourceBindings *srb = nullptr;
QRhiGraphicsPipeline *ps = nullptr;
QVector<QRhiResource *> releasePool;
float rotation = 0;
QRhiResourceUpdateBatch *initialUpdates = nullptr;
int frameCount = 0;
QImage customImage;
QRhiTexture *newTex = nullptr;
QRhiTexture *importedTex = nullptr;
int testStage = 0;
} d;
void Window::customInit()
{
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(cube));
d.releasePool << d.vbuf;
d.vbuf->build();
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
d.releasePool << d.ubuf;
d.ubuf->build();
QImage baseImage(QLatin1String(":/qt256.png"));
d.tex = m_r->newTexture(QRhiTexture::RGBA8, baseImage.size(), 1, QRhiTexture::UsedAsTransferSource);
d.releasePool << d.tex;
d.tex->build();
// As an alternative to what some of the other examples do, prepare an
......@@ -90,9 +95,11 @@ void Window::customInit()
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
d.releasePool << d.sampler;
d.sampler->build();
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
......@@ -100,6 +107,7 @@ void Window::customInit()
d.srb->build();
d.ps = m_r->newGraphicsPipeline();
d.releasePool << d.ps;
d.ps->setDepthTest(true);
d.ps->setDepthWrite(true);
......@@ -147,40 +155,10 @@ void Window::customInit()
void Window::customRelease()
{
if (d.ps) {
d.ps->releaseAndDestroy();
d.ps = nullptr;
}
if (d.srb) {
d.srb->releaseAndDestroy();
d.srb = nullptr;
}
if (d.ubuf) {
d.ubuf->releaseAndDestroy();
d.ubuf = nullptr;
}
if (d.vbuf) {
d.vbuf->releaseAndDestroy();
d.vbuf = nullptr;
}
for (QRhiResource *r : d.releasePool)
r->releaseAndDestroy();
if (d.sampler) {
d.sampler->releaseAndDestroy();
d.sampler = nullptr;
}
if (d.tex) {
d.tex->releaseAndDestroy();
d.tex = nullptr;
}
if (d.newTex) {
d.newTex->releaseAndDestroy();
d.newTex = nullptr;
}
d.releasePool.clear();
}
void Window::customRender()
......@@ -224,6 +202,7 @@ void Window::customRender()
if (d.testStage == 2) {
const QSize sz = d.tex->pixelSize();
d.newTex = m_r->newTexture(QRhiTexture::RGBA8, sz);
d.releasePool << d.newTex;
d.newTex->build();
QImage empty(sz.width(), sz.height(), QImage::Format_RGBA8888);
......@@ -269,6 +248,40 @@ void Window::customRender()
desc.layers.append(layer);
u->uploadTexture(d.newTex, desc);
}
// Exercise texture object export/import.
if (d.testStage == 6) {
QRhiNativeHandles *h = d.tex->nativeHandles();
if (h) {
#ifdef Q_OS_DARWIN
if (graphicsApi == Metal) {
qDebug() << "Metal texture: " << static_cast<QRhiMetalTextureNativeHandles *>(h)->texture;
// Now could cast to id<MTLTexture> and do something with
// it, keeping in mind that copy operations are only done
// in beginPass, while rendering into a texture may only
// have proper results in current_frame + 2, or after a
// finish(). The QRhiTexture still owns the native object.
}
#endif
// omit for other backends, the idea is the same
d.importedTex = m_r->newTexture(QRhiTexture::RGBA8, d.tex->pixelSize());
d.releasePool << d.importedTex;
if (!d.importedTex->buildFrom(h))
qWarning("Texture import failed");
// now d.tex and d.importedTex use the same MTLTexture
// underneath (owned by d.tex)
// switch to showing d.importedTex
auto bindings = d.srb->bindings();
bindings[1].stex.tex = d.importedTex;
d.srb->setBindings(bindings);
d.srb->build();
} else {
qWarning("Accessing native texture object is not supported");
}
}
}
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
......
......@@ -85,6 +85,17 @@ QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &p
{
}
QRhiNativeHandles *QRhiTexture::nativeHandles()
{
return nullptr;
}
bool QRhiTexture::buildFrom(QRhiNativeHandles *src)
{
Q_UNUSED(src);
return false;
}
QRhiSampler::QRhiSampler(QRhiImplementation *rhi,
Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
AddressMode u_, AddressMode v_, AddressMode w_)
......@@ -629,6 +640,11 @@ bool QRhi::isFeatureSupported(QRhi::Feature feature) const
return d->isFeatureSupported(feature);
}
QRhiNativeHandles *QRhi::nativeHandles()
{
return d->nativeHandles();
}
QRhiGraphicsPipeline *QRhi::newGraphicsPipeline()
{
return d->createGraphicsPipeline();
......
......@@ -352,10 +352,15 @@ struct Q_RHI_EXPORT QRhiReadbackDescription
Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiNativeHandles
{
};
class Q_RHI_EXPORT QRhiResource
{
public:
virtual ~QRhiResource();
virtual void release() = 0;
void releaseAndDestroy();
......@@ -471,6 +476,16 @@ public:
virtual bool build() = 0;
// Returns a ptr to a QRhi<backend>TextureNativeHandles struct.
// Ownership of the native objects is not transfered.
virtual QRhiNativeHandles *nativeHandles();
// Calling this instead of build() allows importing an existing native
// texture object (must belong to the same device or a sharing context).
// Note that format, pixelSize, etc. must still be set correctly (typically
// via QRhi::newTexture()). Ownership of the native resource is not taken.
virtual bool buildFrom(QRhiNativeHandles *src);
protected:
QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_,
int sampleCount_, Flags flags_);
......@@ -1220,6 +1235,10 @@ public:
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = QRhiTexture::Flags()) const;
bool isFeatureSupported(QRhi::Feature feature) const;
// Returns a ptr to a QRhi<backend>NativeHandles struct.
// Ownership of the native objects is not transfered.
QRhiNativeHandles *nativeHandles();
protected:
QRhi();
......
......@@ -126,6 +126,7 @@ public:
virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
virtual bool isFeatureSupported(QRhi::Feature) const = 0;
virtual QRhiNativeHandles *nativeHandles() = 0;
bool isCompressedFormat(QRhiTexture::Format format) const;
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
......
......@@ -146,6 +146,9 @@ bool QRhiD3D11::create()
featureLevel = dev->GetFeatureLevel();
}
nativeHandlesStruct.dev = dev;
nativeHandlesStruct.context = context;
return true;
}
......@@ -252,6 +255,11 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
}
}
QRhiNativeHandles *QRhiD3D11::nativeHandles()
{
return &nativeHandlesStruct;
}
QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
......
......@@ -55,6 +55,12 @@ struct Q_RHI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
void *context = nullptr;
};
struct Q_RHI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
{
void *dev;
void *context;
};
QT_END_NAMESPACE
#endif
......@@ -485,6 +485,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
QRhiNativeHandles *nativeHandles() override;
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD);
......@@ -500,6 +501,7 @@ public:
ID3D11DeviceContext1 *context = nullptr;
D3D_FEATURE_LEVEL featureLevel;
IDXGIFactory2 *dxgiFactory = nullptr;
QRhiD3D11NativeHandles nativeHandlesStruct;
bool inFrame = false;
int finishedFrameCount = 0;
......
......@@ -116,6 +116,8 @@ bool QRhiGles2::create()
caps.msaaRenderBuffer = f->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& f->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
nativeHandlesStruct.context = ctx;
return true;
}
......@@ -264,6 +266,11 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
}
}
QRhiNativeHandles *QRhiGles2::nativeHandles()
{
return &nativeHandlesStruct;
}
QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
......
......@@ -62,6 +62,11 @@ struct Q_RHI_EXPORT QRhiGles2InitParams : public QRhiInitParams
QOffscreenSurface *fallbackSurface = nullptr;
};
struct Q_RHI_EXPORT QRhiGles2NativeHandles : public QRhiNativeHandles
{
QOpenGLContext *context;
};
QT_END_NAMESPACE
#endif
......@@ -500,6 +500,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
QRhiNativeHandles *nativeHandles() override;
bool ensureContext(QSurface *surface = nullptr) const;
void executeDeferredReleases();
......@@ -523,6 +524,7 @@ public:
bool inPass = false;
QGles2SwapChain *currentSwapChain = nullptr;
QVector<GLint> supportedCompressedFormats;
QRhiGles2NativeHandles nativeHandlesStruct;
struct DeferredReleaseEntry {
enum Type {
......
......@@ -50,7 +50,18 @@ struct Q_RHI_EXPORT QRhiMetalInitParams : public QRhiInitParams
// API validation.
bool importExistingDevice = false;
void *dev = nullptr;
void *dev = nullptr; // ownership not taken
};
struct Q_RHI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
{
void *dev;
void *cmdQueue;
};
struct Q_RHI_EXPORT QRhiMetalTextureNativeHandles : public QRhiNativeHandles
{
void *texture = nullptr; // id<MTLTexture>
};
QT_END_NAMESPACE
......
......@@ -145,6 +145,7 @@ struct QMetalTextureData
MTLPixelFormat format;
id<MTLTexture> tex = nil;
id<MTLBuffer> stagingBuf[QMTL_FRAMES_IN_FLIGHT];
bool owns = true;
};
struct QMetalSamplerData
......@@ -237,6 +238,9 @@ bool QRhiMetal::create()
d->cmdQueue = [d->dev newCommandQueue];
nativeHandlesStruct.dev = d->dev;
nativeHandlesStruct.cmdQueue = d->cmdQueue;
return true;
}
......@@ -336,6 +340,11 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
}
}
QRhiNativeHandles *QRhiMetal::nativeHandles()
{
return &nativeHandlesStruct;
}
QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
......@@ -1331,14 +1340,17 @@ void QMetalTexture::release()
e.texture.texture = d->tex;
d->tex = nil;
nativeHandlesStruct.texture = nullptr;
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
e.texture.stagingBuffers[i] = d->stagingBuf[i];
d->stagingBuf[i] = nil;
}
QRHI_RES_RHI(QRhiMetal);
rhiD->d->releaseQueue.append(e);
if (d->owns) {
QRHI_RES_RHI(QRhiMetal);
rhiD->d->releaseQueue.append(e);
}
}
static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
......@@ -1502,6 +1514,40 @@ bool QMetalTexture::build()
d->tex = [rhiD->d->dev newTextureWithDescriptor: desc];
[desc release];
d->owns = true;
nativeHandlesStruct.texture = d->tex;
lastActiveFrameSlot = -1;
generation += 1;
return true;
}
QRhiNativeHandles *QMetalTexture::nativeHandles()
{
return &nativeHandlesStruct;
}
bool QMetalTexture::buildFrom(QRhiNativeHandles *src)
{
QRhiMetalTextureNativeHandles *h = static_cast<QRhiMetalTextureNativeHandles *>(src);
if (!h || !h->texture)
return false;
if (d->tex)
release();
QRHI_RES_RHI(QRhiMetal);
d->format = toMetalTextureFormat(m_format, m_flags);
const QSize size = m_pixelSize.isEmpty() ? QSize(16, 16) : m_pixelSize;
const bool hasMipMaps = m_flags.testFlag(MipMapped);
mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
samples = rhiD->effectiveSampleCount(m_sampleCount);
d->tex = (id<MTLTexture>) h->texture;
d->owns = false;
nativeHandlesStruct.texture = d->tex;
lastActiveFrameSlot = -1;
generation += 1;
return true;
......
......@@ -93,8 +93,11 @@ struct QMetalTexture : public QRhiTexture
~QMetalTexture();
void release() override;
bool build() override;
QRhiNativeHandles *nativeHandles() override;
bool buildFrom(QRhiNativeHandles *src) override;
QMetalTextureData *d;
QRhiMetalTextureNativeHandles nativeHandlesStruct;
int mipLevelCount = 0;
int samples = 1;
uint generation = 0;
......@@ -317,6 +320,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
QRhiNativeHandles *nativeHandles() override;
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
......@@ -331,6 +335,7 @@ public:
bool inPass = false;
QMetalSwapChain *currentSwapChain = nullptr;
QSet<QMetalSwapChain *> swapchains;
QRhiMetalNativeHandles nativeHandlesStruct;
QRhiMetalData *d = nullptr;
};
......
......@@ -167,6 +167,7 @@ QRhiVulkan::QRhiVulkan(QRhiInitParams *params)
gfxQueueFamilyIdx = vkparams->gfxQueueFamilyIdx;
gfxQueue = vkparams->gfxQueue;
cmdPool = vkparams->cmdPool;
allocator = vkparams->vmemAllocator;
}
maybeWindow = vkparams->window; // may be null
}
......@@ -281,24 +282,6 @@ bool QRhiVulkan::create()
if (gfxQueueFamilyIdx != -1 && !gfxQueue)
df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
VmaVulkanFunctions afuncs;
afuncs.vkGetPhysicalDeviceProperties = wrap_vkGetPhysicalDeviceProperties;
afuncs.vkGetPhysicalDeviceMemoryProperties = wrap_vkGetPhysicalDeviceMemoryProperties;
afuncs.vkAllocateMemory = wrap_vkAllocateMemory;
afuncs.vkFreeMemory = wrap_vkFreeMemory;
afuncs.vkMapMemory = wrap_vkMapMemory;
afuncs.vkUnmapMemory = wrap_vkUnmapMemory;
afuncs.vkFlushMappedMemoryRanges = wrap_vkFlushMappedMemoryRanges;
afuncs.vkInvalidateMappedMemoryRanges = wrap_vkInvalidateMappedMemoryRanges;
afuncs.vkBindBufferMemory = wrap_vkBindBufferMemory;
afuncs.vkBindImageMemory = wrap_vkBindImageMemory;
afuncs.vkGetBufferMemoryRequirements = wrap_vkGetBufferMemoryRequirements;
afuncs.vkGetImageMemoryRequirements = wrap_vkGetImageMemoryRequirements;
afuncs.vkCreateBuffer = wrap_vkCreateBuffer;
afuncs.vkDestroyBuffer = wrap_vkDestroyBuffer;
afuncs.vkCreateImage = wrap_vkCreateImage;
afuncs.vkDestroyImage = wrap_vkDestroyImage;
f->vkGetPhysicalDeviceProperties(physDev, &physDevProperties);
ubufAlign = physDevProperties.limits.minUniformBufferOffsetAlignment;
texbufAlign = physDevProperties.limits.optimalBufferCopyOffsetAlignment;
......@@ -308,26 +291,53 @@ bool QRhiVulkan::create()
VK_VERSION_MINOR(physDevProperties.driverVersion),
VK_VERSION_PATCH(physDevProperties.driverVersion));
VmaAllocatorCreateInfo allocatorInfo;
memset(&allocatorInfo, 0, sizeof(allocatorInfo));
allocatorInfo.physicalDevice = physDev;
allocatorInfo.device = dev;
allocatorInfo.pVulkanFunctions = &afuncs;
VmaAllocator vmaallocator;
VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
if (err != VK_SUCCESS) {
qWarning("Failed to create allocator: %d", err);
return false;
if (!allocator) {
VmaVulkanFunctions afuncs;
afuncs.vkGetPhysicalDeviceProperties = wrap_vkGetPhysicalDeviceProperties;
afuncs.vkGetPhysicalDeviceMemoryProperties = wrap_vkGetPhysicalDeviceMemoryProperties;
afuncs.vkAllocateMemory = wrap_vkAllocateMemory;
afuncs.vkFreeMemory = wrap_vkFreeMemory;
afuncs.vkMapMemory = wrap_vkMapMemory;
afuncs.vkUnmapMemory = wrap_vkUnmapMemory;
afuncs.vkFlushMappedMemoryRanges = wrap_vkFlushMappedMemoryRanges;
afuncs.vkInvalidateMappedMemoryRanges = wrap_vkInvalidateMappedMemoryRanges;
afuncs.vkBindBufferMemory = wrap_vkBindBufferMemory;
afuncs.vkBindImageMemory = wrap_vkBindImageMemory;
afuncs.vkGetBufferMemoryRequirements = wrap_vkGetBufferMemoryRequirements;
afuncs.vkGetImageMemoryRequirements = wrap_vkGetImageMemoryRequirements;
afuncs.vkCreateBuffer = wrap_vkCreateBuffer;
afuncs.vkDestroyBuffer = wrap_vkDestroyBuffer;
afuncs.vkCreateImage = wrap_vkCreateImage;
afuncs.vkDestroyImage = wrap_vkDestroyImage;
VmaAllocatorCreateInfo allocatorInfo;
memset(&allocatorInfo, 0, sizeof(allocatorInfo));
allocatorInfo.physicalDevice = physDev;
allocatorInfo.device = dev;
allocatorInfo.pVulkanFunctions = &afuncs;
VmaAllocator vmaallocator;
VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
if (err != VK_SUCCESS) {
qWarning("Failed to create allocator: %d", err);
return false;
}
allocator = vmaallocator;
}
allocator = vmaallocator;
VkDescriptorPool pool;
err = createDescriptorPool(&pool);
VkResult err = createDescriptorPool(&pool);
if (err == VK_SUCCESS)
descriptorPools.append(pool);
else
qWarning("Failed to create initial descriptor pool: %d", err);
nativeHandlesStruct.physDev = physDev;
nativeHandlesStruct.dev = dev;
nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
nativeHandlesStruct.gfxQueue = gfxQueue;
nativeHandlesStruct.cmdPool = cmdPool;
nativeHandlesStruct.vmemAllocator = allocator;
return true;
}
......@@ -361,9 +371,8 @@ void QRhiVulkan::destroy()
descriptorPools.clear();
vmaDestroyAllocator(toVmaAllocator(allocator));
if (!importedDevPoolQueue) {
vmaDestroyAllocator(toVmaAllocator(allocator));
if (cmdPool) {
df->vkDestroyCommandPool(dev, cmdPool, nullptr);
cmdPool = VK_NULL_HANDLE;
......@@ -2628,6 +2637,11 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
}
}
QRhiNativeHandles *QRhiVulkan::nativeHandles()
{
return &nativeHandlesStruct;
}
QRhiRenderBuffer *QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
......
......@@ -54,6 +54,7 @@ struct Q_RHI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
int gfxQueueFamilyIdx = -1; // either this or gfxQueue is required [prefer this over gfxQueue]
VkQueue gfxQueue = VK_NULL_HANDLE; // either this or gfxQueueFamilyIdx is required [use this only when importing a QVulkanWindow]
VkCommandPool cmdPool = VK_NULL_HANDLE; // optional
void *vmemAllocator = nullptr; // optional
// optional, only used during init to verify if presenting is supported
// while choosing the graphics queue
......@@ -61,6 +62,16 @@ struct Q_RHI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
QWindow *window = nullptr;
};
struct Q_RHI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
{
VkPhysicalDevice physDev;
VkDevice dev;
int gfxQueueFamilyIdx;
VkQueue gfxQueue;
VkCommandPool cmdPool;
void *vmemAllocator;
};
QT_END_NAMESPACE
#endif
......@@ -386,6 +386,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
QRhiNativeHandles *nativeHandles() override;
VkResult createDescriptorPool(VkDescriptorPool *pool);
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);
......@@ -458,7 +459,7 @@ public:
VkCommandPool cmdPool = VK_NULL_HANDLE;
int gfxQueueFamilyIdx = -1;
VkQueue gfxQueue = VK_NULL_HANDLE;
QVkAllocator allocator;
QVkAllocator allocator = nullptr;
QVulkanFunctions *f = nullptr;
QVulkanDeviceFunctions *df = nullptr;
VkPhysicalDeviceProperties physDevProperties;
......@@ -494,6 +495,7 @@ public:
bool inPass = false;
QVkSwapChain *currentSwapChain = nullptr;
QSet<QVkSwapChain *> swapchains;
QRhiVulkanNativeHandles nativeHandlesStruct;
struct OffscreenFrame {
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
......
beginpass without clear
mtl: reduce set*
resource import/export, what's the interop story
texture export