Bug 1753302 - Part 1. Integrate WebGPU with OffscreenCanvas plumbing. r=gfx-reviewers,jgilbert

Differential Revision: https://phabricator.services.mozilla.com/D141491
This commit is contained in:
Andrew Osmond 2022-04-04 16:42:02 +00:00
parent 524448eb15
commit 3fe3f7ca98
8 changed files with 66 additions and 22 deletions

View File

@ -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),

View File

@ -163,12 +163,10 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
nsCOMPtr<nsIGlobalObject>&& aGlobal, Promise* aPromise);
void CanvasAttrChanged() {
mAttrDirty = true;
ErrorResult dummy;
UpdateContext(nullptr, JS::NullHandleValue, dummy);
}
bool mAttrDirty;
bool mNeutered;
bool mIsWriteOnly;

View File

@ -45,11 +45,21 @@ RefPtr<layers::ImageContainer> OffscreenCanvasDisplayHelper::GetImageContainer()
return mImageContainer;
}
layers::CompositableHandle OffscreenCanvasDisplayHelper::GetCompositableHandle()
const {
MutexAutoLock lock(mMutex);
return mData.mHandle;
}
void OffscreenCanvasDisplayHelper::UpdateContext(
CanvasContextType aType, const Maybe<int32_t>& aChildId) {
MutexAutoLock lock(mMutex);
mImageContainer =
MakeRefPtr<layers::ImageContainer>(layers::ImageContainer::ASYNCHRONOUS);
if (aType != CanvasContextType::WebGPU) {
mImageContainer = MakeRefPtr<layers::ImageContainer>(
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;

View File

@ -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<layers::ImageContainer> GetImageContainer() const;
layers::CompositableHandle GetCompositableHandle() const;
void UpdateContext(CanvasContextType aType, const Maybe<int32_t>& aChildId);
bool CommitFrameToCompositor(nsICanvasRenderingContextInternal* aContext,

View File

@ -1478,4 +1478,11 @@ webgpu::CanvasContext* HTMLCanvasElement::GetWebGPUContext() {
return static_cast<webgpu::CanvasContext*>(GetCurrentContext());
}
CompositableHandle HTMLCanvasElement::GetCompositableHandle() const {
if (mOffscreenDisplay) {
return mOffscreenDisplay->GetCompositableHandle();
}
return CompositableHandle();
}
} // namespace mozilla::dom

View File

@ -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

View File

@ -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() {

View File

@ -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<nsHTMLCanvasFrame*>(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<ImageContainer> container = element->GetImageContainer();
if (container) {
nsHTMLCanvasFrame* canvasFrame =
static_cast<nsHTMLCanvasFrame*>(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;
}