Bug 1878316 - Defer SwapChain drop until readback complete r=lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D201192
This commit is contained in:
sotaro 2024-02-09 22:37:37 +00:00
parent 0aaf858381
commit 2b666cc1a6

View file

@ -4,6 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGPUParent.h" #include "WebGPUParent.h"
#include <unordered_set>
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/ScopeExit.h" #include "mozilla/ScopeExit.h"
#include "mozilla/dom/WebGPUBinding.h" #include "mozilla/dom/WebGPUBinding.h"
@ -153,10 +156,16 @@ class ErrorBuffer {
} }
}; };
struct PendingSwapChainDrop {
layers::RemoteTextureTxnType mTxnType;
layers::RemoteTextureTxnId mTxnId;
};
class PresentationData { class PresentationData {
NS_INLINE_DECL_REFCOUNTING(PresentationData); NS_INLINE_DECL_REFCOUNTING(PresentationData);
public: public:
WeakPtr<WebGPUParent> mParent;
const bool mUseExternalTextureInSwapChain; const bool mUseExternalTextureInSwapChain;
const RawId mDeviceId; const RawId mDeviceId;
const RawId mQueueId; const RawId mQueueId;
@ -166,16 +175,22 @@ class PresentationData {
std::deque<std::shared_ptr<ExternalTexture>> mRecycledExternalTextures; std::deque<std::shared_ptr<ExternalTexture>> mRecycledExternalTextures;
std::unordered_set<layers::RemoteTextureId, layers::RemoteTextureId::HashFn>
mWaitingReadbackTexturesForPresent;
Maybe<PendingSwapChainDrop> mPendingSwapChainDrop;
const uint32_t mSourcePitch; const uint32_t mSourcePitch;
std::vector<RawId> mUnassignedBufferIds MOZ_GUARDED_BY(mBuffersLock); std::vector<RawId> mUnassignedBufferIds MOZ_GUARDED_BY(mBuffersLock);
std::vector<RawId> mAvailableBufferIds MOZ_GUARDED_BY(mBuffersLock); std::vector<RawId> mAvailableBufferIds MOZ_GUARDED_BY(mBuffersLock);
std::vector<RawId> mQueuedBufferIds MOZ_GUARDED_BY(mBuffersLock); std::vector<RawId> mQueuedBufferIds MOZ_GUARDED_BY(mBuffersLock);
Mutex mBuffersLock; Mutex mBuffersLock;
PresentationData(bool aUseExternalTextureInSwapChain, RawId aDeviceId, PresentationData(WebGPUParent* aParent, bool aUseExternalTextureInSwapChain,
RawId aQueueId, const layers::RGBDescriptor& aDesc, RawId aDeviceId, RawId aQueueId,
uint32_t aSourcePitch, const nsTArray<RawId>& aBufferIds) const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch,
: mUseExternalTextureInSwapChain(aUseExternalTextureInSwapChain), const nsTArray<RawId>& aBufferIds)
: mParent(aParent),
mUseExternalTextureInSwapChain(aUseExternalTextureInSwapChain),
mDeviceId(aDeviceId), mDeviceId(aDeviceId),
mQueueId(aQueueId), mQueueId(aQueueId),
mDesc(aDesc), mDesc(aDesc),
@ -861,9 +876,9 @@ ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain(
} }
mRemoteTextureOwner->RegisterTextureOwner(aOwnerId); mRemoteTextureOwner->RegisterTextureOwner(aOwnerId);
auto data = auto data = MakeRefPtr<PresentationData>(this, aUseExternalTextureInSwapChain,
MakeRefPtr<PresentationData>(aUseExternalTextureInSwapChain, aDeviceId, aDeviceId, aQueueId, aDesc,
aQueueId, aDesc, bufferStride, aBufferIds); bufferStride, aBufferIds);
if (!mPresentationDataMap.emplace(aOwnerId, data).second) { if (!mPresentationDataMap.emplace(aOwnerId, data).second) {
NS_ERROR("External image is already registered as WebGPU canvas!"); NS_ERROR("External image is already registered as WebGPU canvas!");
} }
@ -933,6 +948,23 @@ static void ReadbackPresentCallback(ffi::WGPUBufferMapAsyncStatus status,
UniquePtr<ReadbackPresentRequest> req( UniquePtr<ReadbackPresentRequest> req(
reinterpret_cast<ReadbackPresentRequest*>(userdata)); reinterpret_cast<ReadbackPresentRequest*>(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)) { if (!req->mRemoteTextureOwner->IsRegistered(req->mOwnerId)) {
// SwapChain is already Destroyed // SwapChain is already Destroyed
return; 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 // 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 // TODO: this isn't strictly necessary. When WR wants to Lock() the external
// texture, // texture,
@ -1220,6 +1259,13 @@ ipc::IPCResult WebGPUParent::RecvSwapChainDrop(
RefPtr<PresentationData> data = lookup->second.get(); RefPtr<PresentationData> 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 (mRemoteTextureOwner) {
if (aTxnType && aTxnId) { if (aTxnType && aTxnId) {
mRemoteTextureOwner->WaitForTxn(aOwnerId, aTxnType, aTxnId); mRemoteTextureOwner->WaitForTxn(aOwnerId, aTxnType, aTxnId);