diff --git a/dom/canvas/OffscreenCanvas.cpp b/dom/canvas/OffscreenCanvas.cpp index 4b8a3816cadb..b5fe51f411e2 100644 --- a/dom/canvas/OffscreenCanvas.cpp +++ b/dom/canvas/OffscreenCanvas.cpp @@ -48,7 +48,6 @@ OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, layers::TextureType aTextureType, OffscreenCanvasDisplayHelper* aDisplay) : DOMEventTargetHelper(aGlobal), - mAttrDirty(false), mNeutered(false), mIsWriteOnly(false), mWidth(aWidth), diff --git a/dom/canvas/OffscreenCanvas.h b/dom/canvas/OffscreenCanvas.h index af201857ae26..c5dfb644190e 100644 --- a/dom/canvas/OffscreenCanvas.h +++ b/dom/canvas/OffscreenCanvas.h @@ -163,12 +163,10 @@ class OffscreenCanvas final : public DOMEventTargetHelper, nsCOMPtr&& aGlobal, Promise* aPromise); void CanvasAttrChanged() { - mAttrDirty = true; ErrorResult dummy; UpdateContext(nullptr, JS::NullHandleValue, dummy); } - bool mAttrDirty; bool mNeutered; bool mIsWriteOnly; diff --git a/dom/canvas/OffscreenCanvasDisplayHelper.cpp b/dom/canvas/OffscreenCanvasDisplayHelper.cpp index c8f05e6a8c66..8d75cff2f7a5 100644 --- a/dom/canvas/OffscreenCanvasDisplayHelper.cpp +++ b/dom/canvas/OffscreenCanvasDisplayHelper.cpp @@ -45,11 +45,21 @@ RefPtr OffscreenCanvasDisplayHelper::GetImageContainer() return mImageContainer; } +layers::CompositableHandle OffscreenCanvasDisplayHelper::GetCompositableHandle() + const { + MutexAutoLock lock(mMutex); + return mData.mHandle; +} + void OffscreenCanvasDisplayHelper::UpdateContext( CanvasContextType aType, const Maybe& aChildId) { MutexAutoLock lock(mMutex); - mImageContainer = - MakeRefPtr(layers::ImageContainer::ASYNCHRONOUS); + + if (aType != CanvasContextType::WebGPU) { + mImageContainer = MakeRefPtr( + layers::ImageContainer::ASYNCHRONOUS); + } + mType = aType; mContextChildId = aChildId; @@ -82,6 +92,16 @@ bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor( MaybeQueueInvalidateElement(); } + if (mData.mHandle) { + // No need to update the ImageContainer as the presentation itself is + // handled in the compositor process. + return true; + } + + if (!mImageContainer) { + return false; + } + if (mData.mIsOpaque) { flags |= layers::TextureFlags::IS_OPAQUE; format = gfx::SurfaceFormat::B8G8R8X8; diff --git a/dom/canvas/OffscreenCanvasDisplayHelper.h b/dom/canvas/OffscreenCanvasDisplayHelper.h index 970f8c4be5d2..c28f9676b911 100644 --- a/dom/canvas/OffscreenCanvasDisplayHelper.h +++ b/dom/canvas/OffscreenCanvasDisplayHelper.h @@ -28,6 +28,7 @@ struct OffscreenCanvasDisplayData final { bool mIsOpaque = true; bool mIsAlphaPremult = true; mozilla::gl::OriginPos mOriginPos = gl::OriginPos::TopLeft; + mozilla::layers::CompositableHandle mHandle; }; class OffscreenCanvasDisplayHelper final { @@ -41,6 +42,8 @@ class OffscreenCanvasDisplayHelper final { RefPtr GetImageContainer() const; + layers::CompositableHandle GetCompositableHandle() const; + void UpdateContext(CanvasContextType aType, const Maybe& aChildId); bool CommitFrameToCompositor(nsICanvasRenderingContextInternal* aContext, diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 8cc3fd8cac74..a49828db1fb6 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -1478,4 +1478,11 @@ webgpu::CanvasContext* HTMLCanvasElement::GetWebGPUContext() { return static_cast(GetCurrentContext()); } +CompositableHandle HTMLCanvasElement::GetCompositableHandle() const { + if (mOffscreenDisplay) { + return mOffscreenDisplay->GetCompositableHandle(); + } + return CompositableHandle(); +} + } // namespace mozilla::dom diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index 3cd29b289955..a8625bdab5bf 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -347,6 +347,8 @@ class HTMLCanvasElement final : public nsGenericHTMLElement, layers::ImageContainer* GetImageContainer() const { return mImageContainer; } + layers::CompositableHandle GetCompositableHandle() const; + protected: bool mResetLayer; bool mMaybeModified; // we fetched the context, so we may have written to the diff --git a/dom/webgpu/CanvasContext.cpp b/dom/webgpu/CanvasContext.cpp index 7d30d06bd10f..d4b4689faad9 100644 --- a/dom/webgpu/CanvasContext.cpp +++ b/dom/webgpu/CanvasContext.cpp @@ -73,7 +73,14 @@ void CanvasContext::Configure(const dom::GPUCanvasConfiguration& aDesc) { // Force a new frame to be built, which will execute the // `CanvasContextType::WebGPU` switch case in `CreateWebRenderCommands` and // populate the WR user data. - mCanvasElement->InvalidateCanvas(); + if (mCanvasElement) { + mCanvasElement->InvalidateCanvas(); + } else if (mOffscreenCanvas) { + dom::OffscreenCanvasDisplayData data; + data.mSize = {mWidth, mHeight}; + data.mHandle = mHandle; + mOffscreenCanvas->UpdateDisplayData(data); + } } void CanvasContext::Unconfigure() { diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 15d62246592d..ad4fa3952c6a 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -108,27 +108,35 @@ class nsDisplayCanvas final : public nsPaintedDisplayItem { element->HandlePrintCallback(mFrame->PresContext()); if (element->IsOffscreen()) { - // If we are offscreen, then we display via an ImageContainer which is - // updated asynchronously, likely from a worker thread. There is nothing - // to paint until the owner attaches it. + // If we are offscreen, then we either display via an ImageContainer + // which is updated asynchronously, likely from a worker thread, or a + // CompositableHandle managed inside the compositor process. There is + // nothing to paint until the owner attaches it. + + nsHTMLCanvasFrame* canvasFrame = static_cast(mFrame); + nsIntSize canvasSizeInPx = canvasFrame->GetCanvasSize(); + IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx); + AspectRatio intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx); + nsRect area = mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame(); + nsRect dest = nsLayoutUtils::ComputeObjectDestRect( + area, intrinsicSize, intrinsicRatio, mFrame->StylePosition()); + LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits( + dest, mFrame->PresContext()->AppUnitsPerDevPixel()); + RefPtr container = element->GetImageContainer(); if (container) { - nsHTMLCanvasFrame* canvasFrame = - static_cast(mFrame); - nsIntSize canvasSizeInPx = canvasFrame->GetCanvasSize(); - IntrinsicSize intrinsicSize = - IntrinsicSizeFromCanvasSize(canvasSizeInPx); - AspectRatio intrinsicRatio = - IntrinsicRatioFromCanvasSize(canvasSizeInPx); - nsRect area = - mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame(); - nsRect dest = nsLayoutUtils::ComputeObjectDestRect( - area, intrinsicSize, intrinsicRatio, mFrame->StylePosition()); - LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits( - dest, mFrame->PresContext()->AppUnitsPerDevPixel()); aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources, aSc, bounds, bounds); + return true; } + + CompositableHandle handle = element->GetCompositableHandle(); + if (handle) { + aManager->CommandBuilder().PushInProcessImage(this, handle, aBuilder, + aResources, aSc, bounds); + return true; + } + return true; }