diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp index f633c76ac0f1..6603343b91c3 100644 --- a/dom/webgpu/ipc/WebGPUParent.cpp +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -4,6 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGPUParent.h" + +#include + #include "mozilla/PodOperations.h" #include "mozilla/ScopeExit.h" #include "mozilla/dom/WebGPUBinding.h" @@ -153,10 +156,16 @@ class ErrorBuffer { } }; +struct PendingSwapChainDrop { + layers::RemoteTextureTxnType mTxnType; + layers::RemoteTextureTxnId mTxnId; +}; + class PresentationData { NS_INLINE_DECL_REFCOUNTING(PresentationData); public: + WeakPtr mParent; const bool mUseExternalTextureInSwapChain; const RawId mDeviceId; const RawId mQueueId; @@ -166,16 +175,22 @@ class PresentationData { std::deque> mRecycledExternalTextures; + std::unordered_set + mWaitingReadbackTexturesForPresent; + Maybe mPendingSwapChainDrop; + const uint32_t mSourcePitch; std::vector mUnassignedBufferIds MOZ_GUARDED_BY(mBuffersLock); std::vector mAvailableBufferIds MOZ_GUARDED_BY(mBuffersLock); std::vector mQueuedBufferIds MOZ_GUARDED_BY(mBuffersLock); Mutex mBuffersLock; - PresentationData(bool aUseExternalTextureInSwapChain, RawId aDeviceId, - RawId aQueueId, const layers::RGBDescriptor& aDesc, - uint32_t aSourcePitch, const nsTArray& aBufferIds) - : mUseExternalTextureInSwapChain(aUseExternalTextureInSwapChain), + PresentationData(WebGPUParent* aParent, bool aUseExternalTextureInSwapChain, + RawId aDeviceId, RawId aQueueId, + const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch, + const nsTArray& aBufferIds) + : mParent(aParent), + mUseExternalTextureInSwapChain(aUseExternalTextureInSwapChain), mDeviceId(aDeviceId), mQueueId(aQueueId), mDesc(aDesc), @@ -861,9 +876,9 @@ ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain( } mRemoteTextureOwner->RegisterTextureOwner(aOwnerId); - auto data = - MakeRefPtr(aUseExternalTextureInSwapChain, aDeviceId, - aQueueId, aDesc, bufferStride, aBufferIds); + auto data = MakeRefPtr(this, aUseExternalTextureInSwapChain, + aDeviceId, aQueueId, aDesc, + bufferStride, aBufferIds); if (!mPresentationDataMap.emplace(aOwnerId, data).second) { NS_ERROR("External image is already registered as WebGPU canvas!"); } @@ -933,6 +948,23 @@ static void ReadbackPresentCallback(ffi::WGPUBufferMapAsyncStatus status, UniquePtr req( reinterpret_cast(userdata)); + const auto onExit = mozilla::MakeScopeExit([&]() { + auto& waitingTextures = req->mData->mWaitingReadbackTexturesForPresent; + auto it = waitingTextures.find(req->mTextureId); + MOZ_ASSERT(it != waitingTextures.end()); + if (it != waitingTextures.end()) { + waitingTextures.erase(it); + } + if (req->mData->mPendingSwapChainDrop.isSome() && waitingTextures.empty()) { + if (req->mData->mParent) { + auto& pendingDrop = req->mData->mPendingSwapChainDrop.ref(); + req->mData->mParent->RecvSwapChainDrop( + req->mOwnerId, pendingDrop.mTxnType, pendingDrop.mTxnId); + req->mData->mPendingSwapChainDrop = Nothing(); + } + } + }); + if (!req->mRemoteTextureOwner->IsRegistered(req->mOwnerId)) { // SwapChain is already Destroyed return; @@ -1186,6 +1218,13 @@ ipc::IPCResult WebGPUParent::RecvSwapChainPresent( } } + auto& waitingTextures = data->mWaitingReadbackTexturesForPresent; + auto it = waitingTextures.find(aRemoteTextureId); + MOZ_ASSERT(it == waitingTextures.end()); + if (it == waitingTextures.end()) { + waitingTextures.emplace(aRemoteTextureId); + } + // step 4: request the pixels to be copied into the external texture // TODO: this isn't strictly necessary. When WR wants to Lock() the external // texture, @@ -1220,6 +1259,13 @@ ipc::IPCResult WebGPUParent::RecvSwapChainDrop( RefPtr data = lookup->second.get(); + auto waitingCount = data->mWaitingReadbackTexturesForPresent.size(); + if (waitingCount > 0) { + // Defer SwapChainDrop until readback complete + data->mPendingSwapChainDrop = Some(PendingSwapChainDrop{aTxnType, aTxnId}); + return IPC_OK(); + } + if (mRemoteTextureOwner) { if (aTxnType && aTxnId) { mRemoteTextureOwner->WaitForTxn(aOwnerId, aTxnType, aTxnId);