diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index f98bf4842181..ad91742534cb 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -413,19 +413,24 @@ void ClientWebGLContext::EndComposition() { // - -void ClientWebGLContext::Present(WebGLFramebufferJS* const fb, - const layers::TextureType type) { - if (!mIsCanvasDirty && !fb) return; - mIsCanvasDirty = false; +void ClientWebGLContext::Present(WebGLFramebufferJS* const xrFb, + const layers::TextureType type, + const bool webvr) { + if (!mIsCanvasDirty && !xrFb) return; + if (!xrFb) { + mIsCanvasDirty = false; + } - Run(fb ? fb->mId : 0, type); + Run(xrFb ? xrFb->mId : 0, type, webvr); } Maybe ClientWebGLContext::GetFrontBuffer( - WebGLFramebufferJS* const fb) { - return Run(fb ? fb->mId : 0); + WebGLFramebufferJS* const fb, bool vr) { + return Run(fb ? fb->mId : 0, vr); } +void ClientWebGLContext::ClearVRSwapChain() { Run(); } + // - already_AddRefed ClientWebGLContext::GetCanvasLayer( diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h index ca21083ebc14..a1440d27a8bb 100644 --- a/dom/canvas/ClientWebGLContext.h +++ b/dom/canvas/ClientWebGLContext.h @@ -992,11 +992,15 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, } void GetContextAttributes(dom::Nullable& retval); - void Present(WebGLFramebufferJS*, layers::TextureType); - Maybe GetFrontBuffer(WebGLFramebufferJS*); + void Present(WebGLFramebufferJS*, layers::TextureType, + const bool webvr = false); + Maybe GetFrontBuffer(WebGLFramebufferJS*, + const bool webvr = false); RefPtr GetFrontBufferSnapshot( bool requireAlphaPremult = true) override; + void ClearVRSwapChain(); + private: RefPtr BackBufferSnapshot(); void DoReadPixels(const webgl::ReadPixelsDesc&, Range) const; diff --git a/dom/canvas/HostWebGLContext.cpp b/dom/canvas/HostWebGLContext.cpp index f61c08ef8ad5..e0fdc0a74a9c 100644 --- a/dom/canvas/HostWebGLContext.cpp +++ b/dom/canvas/HostWebGLContext.cpp @@ -107,8 +107,8 @@ void HostWebGLContext::JsWarning(const std::string& text) const { } Maybe HostWebGLContext::GetFrontBuffer( - const ObjectId fb) const { - return mContext->GetFrontBuffer(AutoResolve(fb)); + const ObjectId xrFb, const bool webvr) const { + return mContext->GetFrontBuffer(AutoResolve(xrFb), webvr); } ////////////////////////////////////////////// diff --git a/dom/canvas/HostWebGLContext.h b/dom/canvas/HostWebGLContext.h index 5ac292fb79d7..b50ec187b5f3 100644 --- a/dom/canvas/HostWebGLContext.h +++ b/dom/canvas/HostWebGLContext.h @@ -184,15 +184,19 @@ class HostWebGLContext final : public SupportsWeakPtr { mContext->SetCompositableHost(compositableHost); } - void Present(const ObjectId fb, const layers::TextureType t) const { - return (void)mContext->Present(AutoResolve(fb), t); + void Present(const ObjectId xrFb, const layers::TextureType t, + const bool webvr) const { + return (void)mContext->Present(AutoResolve(xrFb), t, webvr); } - Maybe GetFrontBuffer(ObjectId fb) const; + Maybe GetFrontBuffer(ObjectId xrFb, + const bool webvr) const; RefPtr GetFrontBufferSnapshot() const { return mContext->GetFrontBufferSnapshot(); } + void ClearVRSwapChain() { mContext->ClearVRSwapChain(); } + void Resize(const uvec2& size) { return mContext->Resize(size); } uvec2 DrawingBufferSize() { return mContext->DrawingBufferSize(); } diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index b3f56b8b05ca..16674492d789 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -972,16 +972,20 @@ bool WebGLContext::PresentIntoXR(gl::SwapChain& swapChain, return true; } -void WebGLContext::Present(WebGLFramebuffer* const fb, - const layers::TextureType consumerType) { +void WebGLContext::Present(WebGLFramebuffer* const xrFb, + const layers::TextureType consumerType, + const bool webvr) { const FuncScope funcScope(*this, ""); if (IsContextLost()) return; - auto swapChain = &mSwapChain; + auto swapChain = webvr ? &mWebVRSwapChain : &mSwapChain; + if (xrFb) { + swapChain = &xrFb->mOpaqueSwapChain; + } const gl::MozFramebuffer* maybeFB = nullptr; - if (fb) { - swapChain = &fb->mOpaqueSwapChain; - maybeFB = fb->mOpaque.get(); + if (xrFb) { + swapChain = &xrFb->mOpaqueSwapChain; + maybeFB = xrFb->mOpaque.get(); } else { mResolvedDefaultFB = nullptr; } @@ -1006,10 +1010,10 @@ void WebGLContext::Present(WebGLFramebuffer* const fb, } Maybe WebGLContext::GetFrontBuffer( - WebGLFramebuffer* const fb) { - auto swapChain = &mSwapChain; - if (fb) { - swapChain = &fb->mOpaqueSwapChain; + WebGLFramebuffer* const xrFb, const bool webvr) { + auto swapChain = webvr ? &mWebVRSwapChain : &mSwapChain; + if (xrFb) { + swapChain = &xrFb->mOpaqueSwapChain; } const auto& front = swapChain->FrontBuffer(); if (!front) return {}; @@ -1090,6 +1094,8 @@ RefPtr WebGLContext::GetFrontBufferSnapshot() { return surf; } +void WebGLContext::ClearVRSwapChain() { mWebVRSwapChain.ClearPool(); } + // ------------------------ RefPtr GetTempSurface(const gfx::IntSize& aSize, diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 97b3316c25cc..8a8457e12c28 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -483,13 +483,15 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr { // Present to compositor private: bool PresentInto(gl::SwapChain& swapChain); - bool PresentIntoXR(gl::SwapChain& swapChain, const gl::MozFramebuffer& fb); + bool PresentIntoXR(gl::SwapChain& swapChain, const gl::MozFramebuffer& xrFb); public: - void Present(WebGLFramebuffer*, layers::TextureType); + void Present(WebGLFramebuffer*, layers::TextureType, const bool webvr); RefPtr GetFrontBufferSnapshot(); - Maybe GetFrontBuffer(WebGLFramebuffer*); + Maybe GetFrontBuffer(WebGLFramebuffer*, + const bool webvr); + void ClearVRSwapChain(); void RunContextLossTimer(); void CheckForContextLoss(); @@ -1214,6 +1216,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr { mutable UniquePtr mResolvedDefaultFB; gl::SwapChain mSwapChain; + gl::SwapChain mWebVRSwapChain; // -- diff --git a/dom/canvas/WebGLMethodDispatcher.h b/dom/canvas/WebGLMethodDispatcher.h index d76ad0d13164..16e53022d816 100644 --- a/dom/canvas/WebGLMethodDispatcher.h +++ b/dom/canvas/WebGLMethodDispatcher.h @@ -172,6 +172,7 @@ DEFINE_ASYNC(HostWebGLContext::EndQuery) DEFINE_ASYNC(HostWebGLContext::QueryCounter) DEFINE_SYNC(HostWebGLContext::GetQueryParameter) DEFINE_ASYNC(HostWebGLContext::SetFramebufferIsInOpaqueRAF) +DEFINE_ASYNC(HostWebGLContext::ClearVRSwapChain) #undef DEFINE_METHOD_HELPER #undef DEFINE_ASYNC diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index de851784d0b8..dc468baa7a44 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -16,16 +16,44 @@ namespace mozilla::gl { // - // SwapChainPresenter +// We need to apply pooling on Android because of the AndroidSurface slow +// destructor bugs. They cause a noticeable performance hit. See bug +// #1646073. +static constexpr size_t kPoolSize = +#if defined(MOZ_WIDGET_ANDROID) + 4; +#else + 0; +#endif + UniquePtr SwapChain::Acquire(const gfx::IntSize& size) { MOZ_ASSERT(mFactory); - auto back = mFactory->CreateShared(size); - if (!back) return nullptr; + + std::shared_ptr surf; + if (!mPool.empty() && mPool.front()->mDesc.size != size) { + mPool = {}; + } + if (kPoolSize && mPool.size() == kPoolSize) { + surf = mPool.front(); + mPool.pop(); + } + if (!surf) { + auto uniquePtrSurf = mFactory->CreateShared(size); + if (!uniquePtrSurf) return nullptr; + surf.reset(uniquePtrSurf.release()); + } + mPool.push(surf); + while (mPool.size() > kPoolSize) { + mPool.pop(); + } auto ret = MakeUnique(*this); - ret->SwapBackBuffer(std::move(back)); + ret->SwapBackBuffer(std::move(surf)); return ret; } +void SwapChain::ClearPool() { mPool = {}; } + // - SwapChainPresenter::SwapChainPresenter(SwapChain& swapChain) @@ -45,8 +73,8 @@ SwapChainPresenter::~SwapChainPresenter() { } } -UniquePtr SwapChainPresenter::SwapBackBuffer( - UniquePtr back) { +std::shared_ptr SwapChainPresenter::SwapBackBuffer( + std::shared_ptr back) { if (mBackBuffer) { mBackBuffer->UnlockProd(); mBackBuffer->ProducerRelease(); diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index e5c104115628..ea67518ab66e 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -22,6 +22,9 @@ #include "mozilla/UniquePtr.h" #include "SurfaceTypes.h" +#include +#include + namespace mozilla { namespace gl { @@ -33,7 +36,7 @@ class SwapChainPresenter final { friend class SwapChain; SwapChain* mSwapChain; - UniquePtr mBackBuffer; + std::shared_ptr mBackBuffer; public: explicit SwapChainPresenter(SwapChain& swapChain); @@ -41,7 +44,7 @@ class SwapChainPresenter final { const auto& BackBuffer() const { return mBackBuffer; } - UniquePtr SwapBackBuffer(UniquePtr); + std::shared_ptr SwapBackBuffer(std::shared_ptr); GLuint Fb() const; }; @@ -54,13 +57,17 @@ class SwapChain final { UniquePtr mFactory; private: - UniquePtr mFrontBuffer; + std::shared_ptr mFrontBuffer; SwapChainPresenter* mPresenter = nullptr; + private: + std::queue> mPool; + public: SwapChain(); virtual ~SwapChain(); + void ClearPool(); const auto& FrontBuffer() const { return mFrontBuffer; } UniquePtr Acquire(const gfx::IntSize&); }; diff --git a/gfx/vr/ipc/VRLayerChild.cpp b/gfx/vr/ipc/VRLayerChild.cpp index f46d545d56ea..330a865bb97f 100644 --- a/gfx/vr/ipc/VRLayerChild.cpp +++ b/gfx/vr/ipc/VRLayerChild.cpp @@ -92,8 +92,8 @@ void VRLayerChild::SubmitFrame(const VRDisplayInfo& aDisplayInfo) { texType = layers::TextureType::AndroidNativeWindow; } - webgl->Present(mFramebuffer, texType); - mThisFrameTextureDesc = webgl->GetFrontBuffer(mFramebuffer); + webgl->Present(mFramebuffer, texType, true); + mThisFrameTextureDesc = webgl->GetFrontBuffer(mFramebuffer, true); } mLastSubmittedFrameId = frameId; @@ -112,6 +112,10 @@ bool VRLayerChild::IsIPCOpen() { return mIPCOpen; } void VRLayerChild::ClearSurfaces() { mThisFrameTextureDesc = Nothing(); mLastFrameTextureDesc = Nothing(); + const auto& webgl = mCanvasElement->GetWebGLContext(); + if (!mFramebuffer && webgl) { + webgl->ClearVRSwapChain(); + } } void VRLayerChild::ActorDestroy(ActorDestroyReason aWhy) { mIPCOpen = false; }