diff --git a/examples/rhi/sharedresource/sharedresource.cpp b/examples/rhi/sharedresource/sharedresource.cpp index f743777572e69eafc5c76d17347ee17be5e05dfc..f2d57babfe4b3ff5abb7264ce30254e86f415ca8 100644 --- a/examples/rhi/sharedresource/sharedresource.cpp +++ b/examples/rhi/sharedresource/sharedresource.cpp @@ -563,6 +563,8 @@ int main(int argc, char **argv) windowA.setPosition(windowA.position() - QPoint(200, 200)); windowB.setPosition(windowB.position() + QPoint(200, 200)); + windowA.raise(); + windowB.raise(); result = app.exec(); } diff --git a/src/rhi/qrhimetal.mm b/src/rhi/qrhimetal.mm index 7712ac9f7329a6ac7cbe1165de9755d93d1e2166..cac295bae04b0f22acf1ba8d162643670832ef5d 100644 --- a/src/rhi/qrhimetal.mm +++ b/src/rhi/qrhimetal.mm @@ -160,6 +160,8 @@ struct QRhiMetalData }; QVector releaseQueue; + static void executeDeferredReleasesOnRshNow(QVector *rshRelQueue); + struct OffscreenFrame { OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { } bool active = false; @@ -340,7 +342,8 @@ bool QRhiMetal::create(QRhi::Flags flags) // an option when capturing, and becomes especially useful when having // multiple windows with multiple QRhis. d->captureScope = [d->captureMgr newCaptureScopeWithCommandQueue: d->cmdQueue]; - d->captureScope.label = @"Qt capture scope"; + const QString label = QString::asprintf("Qt capture scope for QRhi %p", this); + d->captureScope.label = label.toNSString(); } #if defined(Q_OS_MACOS) @@ -400,8 +403,14 @@ void QRhiMetal::destroy() if (rsh) { if (--rsh->rhiCount == 0) { + if (rsh->d_metal.releaseQueue) { + auto rshRelQueue = static_cast *>(rsh->d_metal.releaseQueue); + QRhiMetalData::executeDeferredReleasesOnRshNow(rshRelQueue); + delete rshRelQueue; + } [(id) rsh->d_metal.dev release]; rsh->d_metal.dev = nullptr; + rsh->d_metal.releaseQueue = nullptr; } } } @@ -1502,6 +1511,55 @@ void QRhiMetal::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource enqueueResourceUpdates(cb, resourceUpdates); } +static void qrhimtl_releaseBuffer(const QRhiMetalData::DeferredReleaseEntry &e) +{ + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + [e.buffer.buffers[i] release]; +} + +static void qrhimtl_releaseRenderBuffer(const QRhiMetalData::DeferredReleaseEntry &e) +{ + [e.renderbuffer.texture release]; +} + +static void qrhimtl_releaseTexture(const QRhiMetalData::DeferredReleaseEntry &e) +{ + [e.texture.texture release]; + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + [e.texture.stagingBuffers[i] release]; +} + +static void qrhimtl_releaseSampler(const QRhiMetalData::DeferredReleaseEntry &e) +{ + [e.sampler.samplerState release]; +} + +void QRhiMetalData::executeDeferredReleasesOnRshNow(QVector *rshRelQueue) +{ + for (int i = rshRelQueue->count() - 1; i >= 0; --i) { + const QRhiMetalData::DeferredReleaseEntry &e((*rshRelQueue)[i]); + // only need to handle resources that report isShareable() == true + switch (e.type) { + case QRhiMetalData::DeferredReleaseEntry::Buffer: + qrhimtl_releaseBuffer(e); + break; + case QRhiMetalData::DeferredReleaseEntry::RenderBuffer: + qrhimtl_releaseRenderBuffer(e); + break; + case QRhiMetalData::DeferredReleaseEntry::Texture: + qrhimtl_releaseTexture(e); + break; + case QRhiMetalData::DeferredReleaseEntry::Sampler: + qrhimtl_releaseSampler(e); + break; + default: + Q_UNREACHABLE(); + break; + } + rshRelQueue->removeAt(i); + } +} + void QRhiMetal::executeDeferredReleases(bool forced) { for (int i = d->releaseQueue.count() - 1; i >= 0; --i) { @@ -1509,19 +1567,16 @@ void QRhiMetal::executeDeferredReleases(bool forced) if (forced || currentFrameSlot == e.lastActiveFrameSlot || e.lastActiveFrameSlot < 0) { switch (e.type) { case QRhiMetalData::DeferredReleaseEntry::Buffer: - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) - [e.buffer.buffers[i] release]; + qrhimtl_releaseBuffer(e); break; case QRhiMetalData::DeferredReleaseEntry::RenderBuffer: - [e.renderbuffer.texture release]; + qrhimtl_releaseRenderBuffer(e); break; case QRhiMetalData::DeferredReleaseEntry::Texture: - [e.texture.texture release]; - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) - [e.texture.stagingBuffers[i] release]; + qrhimtl_releaseTexture(e); break; case QRhiMetalData::DeferredReleaseEntry::Sampler: - [e.sampler.samplerState release]; + qrhimtl_releaseSampler(e); break; case QRhiMetalData::DeferredReleaseEntry::StagingBuffer: [e.stagingBuffer.buffer release]; @@ -1562,6 +1617,17 @@ void QRhiMetal::finishActiveReadbacks(bool forced) f(); } +static void addToRshReleaseQueue(QRhiResourceSharingHostPrivate *rsh, const QRhiMetalData::DeferredReleaseEntry &e) +{ + QVector *rshRelQueue = + static_cast *>(rsh->d_metal.releaseQueue); + if (!rshRelQueue) { + rshRelQueue = new QVector; + rsh->d_metal.releaseQueue = rshRelQueue; + } + rshRelQueue->append(e); +} + QMetalBuffer::QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size) : QRhiBuffer(rhi, type, usage, size), d(new QMetalBufferData) @@ -1575,6 +1641,11 @@ QMetalBuffer::~QMetalBuffer() delete d; } +bool QMetalBuffer::isShareable() const +{ + return true; +} + void QMetalBuffer::release() { if (!d->buf[0]) @@ -1590,17 +1661,23 @@ void QMetalBuffer::release() d->pendingUpdates[i].clear(); } - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - - QRHI_PROF; - QRHI_PROF_F(releaseBuffer(this)); - - rhiD->unregisterResource(this); + if (!orphanedWithRsh) { + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + QRHI_PROF; + QRHI_PROF_F(releaseBuffer(this)); + rhiD->unregisterResource(this); + } else { + // associated rhi is already gone, queue the deferred release to the rsh instead + addToRshReleaseQueue(orphanedWithRsh, e); + } } bool QMetalBuffer::build() { + if (!QRhiImplementation::orphanCheck(this)) + return false; + if (d->buf[0]) release(); @@ -1655,6 +1732,11 @@ QMetalRenderBuffer::~QMetalRenderBuffer() delete d; } +bool QMetalRenderBuffer::isShareable() const +{ + return true; +} + void QMetalRenderBuffer::release() { if (!d->tex) @@ -1667,17 +1749,22 @@ void QMetalRenderBuffer::release() e.renderbuffer.texture = d->tex; d->tex = nil; - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - - QRHI_PROF; - QRHI_PROF_F(releaseRenderBuffer(this)); - - rhiD->unregisterResource(this); + if (!orphanedWithRsh) { + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + QRHI_PROF; + QRHI_PROF_F(releaseRenderBuffer(this)); + rhiD->unregisterResource(this); + } else { + addToRshReleaseQueue(orphanedWithRsh, e); + } } bool QMetalRenderBuffer::build() { + if (!QRhiImplementation::orphanCheck(this)) + return false; + if (d->tex) release(); @@ -1753,6 +1840,11 @@ QMetalTexture::~QMetalTexture() delete d; } +bool QMetalTexture::isShareable() const +{ + return true; +} + void QMetalTexture::release() { if (!d->tex) @@ -1771,13 +1863,15 @@ void QMetalTexture::release() d->stagingBuf[i] = nil; } - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - - QRHI_PROF; - QRHI_PROF_F(releaseTexture(this)); - - rhiD->unregisterResource(this); + if (!orphanedWithRsh) { + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + QRHI_PROF; + QRHI_PROF_F(releaseTexture(this)); + rhiD->unregisterResource(this); + } else { + addToRshReleaseQueue(orphanedWithRsh, e); + } } static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags) @@ -1899,7 +1993,8 @@ static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QR bool QMetalTexture::prepareBuild(QSize *adjustedSize) { - QRHI_RES_RHI(QRhiMetal); + if (!QRhiImplementation::orphanCheck(this)) + return false; if (d->tex) release(); @@ -1908,6 +2003,7 @@ bool QMetalTexture::prepareBuild(QSize *adjustedSize) const bool isCube = m_flags.testFlag(CubeMap); const bool hasMipMaps = m_flags.testFlag(MipMapped); + QRHI_RES_RHI(QRhiMetal); d->format = toMetalTextureFormat(m_format, m_flags); mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1; samples = rhiD->effectiveSampleCount(m_sampleCount); @@ -1930,8 +2026,6 @@ bool QMetalTexture::prepareBuild(QSize *adjustedSize) bool QMetalTexture::build() { - QRHI_RES_RHI(QRhiMetal); - QSize size; if (!prepareBuild(&size)) return false; @@ -1955,6 +2049,7 @@ bool QMetalTexture::build() if (m_flags.testFlag(RenderTarget)) desc.usage |= MTLTextureUsageRenderTarget; + QRHI_RES_RHI(QRhiMetal); d->tex = [rhiD->d->dev newTextureWithDescriptor: desc]; [desc release]; @@ -1975,8 +2070,6 @@ bool QMetalTexture::build() bool QMetalTexture::buildFrom(const QRhiNativeHandles *src) { - QRHI_RES_RHI(QRhiMetal); - const QRhiMetalTextureNativeHandles *h = static_cast(src); if (!h || !h->texture) return false; @@ -1994,6 +2087,7 @@ bool QMetalTexture::buildFrom(const QRhiNativeHandles *src) lastActiveFrameSlot = -1; generation += 1; + QRHI_RES_RHI(QRhiMetal); rhiD->registerResource(this); return true; } @@ -2015,6 +2109,11 @@ QMetalSampler::~QMetalSampler() delete d; } +bool QMetalSampler::isShareable() const +{ + return true; +} + void QMetalSampler::release() { if (!d->samplerState) @@ -2027,10 +2126,13 @@ void QMetalSampler::release() e.sampler.samplerState = d->samplerState; d->samplerState = nil; - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - - rhiD->unregisterResource(this); + if (!orphanedWithRsh) { + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + rhiD->unregisterResource(this); + } else { + addToRshReleaseQueue(orphanedWithRsh, e); + } } static inline MTLSamplerMinMagFilter toMetalFilter(QRhiSampler::Filter f) @@ -2082,6 +2184,9 @@ static inline MTLSamplerAddressMode toMetalAddressMode(QRhiSampler::AddressMode bool QMetalSampler::build() { + if (!QRhiImplementation::orphanCheck(this)) + return false; + if (d->samplerState) release(); diff --git a/src/rhi/qrhimetal_p.h b/src/rhi/qrhimetal_p.h index 7157e803d73dc32d8f055cc2dc2c27bf2aff5c2d..2e3da955220d851e36edd496aa68326b5b7a6c45 100644 --- a/src/rhi/qrhimetal_p.h +++ b/src/rhi/qrhimetal_p.h @@ -57,6 +57,7 @@ struct QMetalBuffer : public QRhiBuffer { QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size); ~QMetalBuffer(); + bool isShareable() const override; void release() override; bool build() override; @@ -73,6 +74,7 @@ struct QMetalRenderBuffer : public QRhiRenderBuffer QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags); ~QMetalRenderBuffer(); + bool isShareable() const override; void release() override; bool build() override; QRhiTexture::Format backingFormat() const override; @@ -91,6 +93,7 @@ struct QMetalTexture : public QRhiTexture QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int sampleCount, Flags flags); ~QMetalTexture(); + bool isShareable() const override; void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; @@ -114,6 +117,7 @@ struct QMetalSampler : public QRhiSampler QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w); ~QMetalSampler(); + bool isShareable() const override; void release() override; bool build() override; diff --git a/src/rhi/qrhirsh_p.h b/src/rhi/qrhirsh_p.h index 9c7e4cee808afa6af4514157fc2fd5db411a115a..8dff9bd25abeb6d4b87dfa46bfce338228509960 100644 --- a/src/rhi/qrhirsh_p.h +++ b/src/rhi/qrhirsh_p.h @@ -91,6 +91,7 @@ public: #ifdef Q_OS_DARWIN struct { void *dev = nullptr; + void *releaseQueue = nullptr; } d_metal; #endif }; diff --git a/todo.txt b/todo.txt index 710288f54c7e8d901d0364d9a65de371d40afec5..58348e923eb2c491f182721bff0c8fc7502bf45c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,9 @@ -res.sh.: mtl +event res.sh.: example to show read/write same texture -threading with rsh with resource - more external sync needed +threading with rsh with resource - more external sync needed? advanced blend modes gl: tex formats (texture, readback) -gl: srgb +gl: srgb? (glEnable and co.) should istexformatsupported should check srgb combinations vk: image in wrong layout when beginFrame-endFrame without a pass in it cbuffer alignment rules - some things fail to translate (to hlsl e.g. with structs), which is fine but how to mitigate @@ -48,6 +48,7 @@ dxc for d3d as an alternative to fxc? hlsl -> dxc -> spirv -> spirv-cross hmmm... +++ done +res.sh.: mtl res.sh.: gl res.sh.: exercise it in multiwindow_threaded too res.sh.: vk, d3d