1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "mozilla/dom/WebGPUBinding.h"
7 #include "CanvasContext.h"
8 #include "SwapChain.h"
9 #include "nsDisplayList.h"
10 #include "LayerUserData.h"
11 #include "mozilla/dom/HTMLCanvasElement.h"
12 #include "mozilla/layers/CompositorManagerChild.h"
13 #include "mozilla/layers/RenderRootStateManager.h"
14 #include "mozilla/layers/WebRenderBridgeChild.h"
15 #include "ipc/WebGPUChild.h"
16
17 namespace mozilla {
18 namespace webgpu {
19
20 NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasContext)21 NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasContext)
22
23 GPU_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasContext, mSwapChain,
24 mCanvasElement, mOffscreenCanvas)
25
26 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasContext)
27 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
28 NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
29 NS_INTERFACE_MAP_ENTRY(nsISupports)
30 NS_INTERFACE_MAP_END
31
32 CanvasContext::CanvasContext()
33 : mExternalImageId(layers::CompositorManagerChild::GetInstance()
34 ->GetNextExternalImageId()) {}
35
~CanvasContext()36 CanvasContext::~CanvasContext() {
37 Cleanup();
38 RemovePostRefreshObserver();
39 }
40
Cleanup()41 void CanvasContext::Cleanup() {
42 if (mSwapChain) {
43 mSwapChain->Destroy(mExternalImageId);
44 mSwapChain = nullptr;
45 }
46 if (mRenderRootStateManager && mImageKey) {
47 mRenderRootStateManager->AddImageKeyForDiscard(mImageKey.value());
48 mRenderRootStateManager = nullptr;
49 mImageKey.reset();
50 }
51 }
52
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)53 JSObject* CanvasContext::WrapObject(JSContext* aCx,
54 JS::Handle<JSObject*> aGivenProto) {
55 return dom::GPUCanvasContext_Binding::Wrap(aCx, this, aGivenProto);
56 }
57
GetCanvasLayer(nsDisplayListBuilder * aBuilder,layers::Layer * aOldLayer,layers::LayerManager * aManager)58 already_AddRefed<layers::Layer> CanvasContext::GetCanvasLayer(
59 nsDisplayListBuilder* aBuilder, layers::Layer* aOldLayer,
60 layers::LayerManager* aManager) {
61 return nullptr;
62 }
63
UpdateWebRenderCanvasData(nsDisplayListBuilder * aBuilder,WebRenderCanvasData * aCanvasData)64 bool CanvasContext::UpdateWebRenderCanvasData(
65 nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
66 return true;
67 }
68
GetSwapChainPreferredFormat(Adapter &) const69 dom::GPUTextureFormat CanvasContext::GetSwapChainPreferredFormat(
70 Adapter&) const {
71 return dom::GPUTextureFormat::Bgra8unorm;
72 }
73
ConfigureSwapChain(const dom::GPUSwapChainDescriptor & aDesc,ErrorResult & aRv)74 RefPtr<SwapChain> CanvasContext::ConfigureSwapChain(
75 const dom::GPUSwapChainDescriptor& aDesc, ErrorResult& aRv) {
76 Cleanup();
77
78 gfx::SurfaceFormat format;
79 switch (aDesc.mFormat) {
80 case dom::GPUTextureFormat::Rgba8unorm:
81 format = gfx::SurfaceFormat::R8G8B8A8;
82 break;
83 case dom::GPUTextureFormat::Bgra8unorm:
84 format = gfx::SurfaceFormat::B8G8R8A8;
85 break;
86 default:
87 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
88 return nullptr;
89 }
90
91 dom::GPUExtent3DDict extent;
92 extent.mWidth = mWidth;
93 extent.mHeight = mHeight;
94 extent.mDepthOrArrayLayers = 1;
95 mSwapChain = new SwapChain(aDesc, extent, mExternalImageId, format);
96
97 // Force a new frame to be built, which will execute the
98 // `CanvasContextType::WebGPU` switch case in `CreateWebRenderCommands` and
99 // populate the WR user data.
100 mCanvasElement->InvalidateCanvas();
101
102 mSwapChain->GetCurrentTexture()->mTargetCanvasElement = mCanvasElement;
103 return mSwapChain;
104 }
105
GetImageKey() const106 Maybe<wr::ImageKey> CanvasContext::GetImageKey() const { return mImageKey; }
107
CreateImageKey(layers::RenderRootStateManager * aManager)108 wr::ImageKey CanvasContext::CreateImageKey(
109 layers::RenderRootStateManager* aManager) {
110 const auto key = aManager->WrBridge()->GetNextImageKey();
111 mRenderRootStateManager = aManager;
112 mImageKey = Some(key);
113 return key;
114 }
115
UpdateWebRenderLocalCanvasData(layers::WebRenderLocalCanvasData * aCanvasData)116 bool CanvasContext::UpdateWebRenderLocalCanvasData(
117 layers::WebRenderLocalCanvasData* aCanvasData) {
118 if (!mSwapChain || !mSwapChain->GetParent()) {
119 return false;
120 }
121
122 const auto size =
123 nsIntSize(AssertedCast<int>(mWidth), AssertedCast<int>(mHeight));
124 if (mSwapChain->mSize != size) {
125 const auto gfxFormat = mSwapChain->mGfxFormat;
126 dom::GPUSwapChainDescriptor desc;
127 desc.mFormat = static_cast<dom::GPUTextureFormat>(mSwapChain->mFormat);
128 desc.mUsage = mSwapChain->mUsage;
129 desc.mDevice = mSwapChain->GetParent();
130
131 mSwapChain->Destroy(mExternalImageId);
132 mExternalImageId =
133 layers::CompositorManagerChild::GetInstance()->GetNextExternalImageId();
134
135 dom::GPUExtent3DDict extent;
136 extent.mWidth = size.width;
137 extent.mHeight = size.height;
138 extent.mDepthOrArrayLayers = 1;
139 mSwapChain = new SwapChain(desc, extent, mExternalImageId, gfxFormat);
140 }
141
142 aCanvasData->mGpuBridge = mSwapChain->GetParent()->GetBridge().get();
143 aCanvasData->mGpuTextureId = mSwapChain->GetCurrentTexture()->mId;
144 aCanvasData->mExternalImageId = mExternalImageId;
145 aCanvasData->mFormat = mSwapChain->mGfxFormat;
146 return true;
147 }
148
149 } // namespace webgpu
150 } // namespace mozilla
151