CanvasManagerParent.cpp (8947B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CanvasManagerParent.h" 8 #include "gfxPlatform.h" 9 #include "mozilla/dom/WebGLParent.h" 10 #include "mozilla/gfx/CanvasRenderThread.h" 11 #include "mozilla/gfx/gfxVars.h" 12 #include "mozilla/gfx/GPUParent.h" 13 #include "mozilla/ipc/Endpoint.h" 14 #include "mozilla/layers/CanvasTranslator.h" 15 #include "mozilla/layers/CompositorThread.h" 16 #include "mozilla/layers/ISurfaceAllocator.h" 17 #include "mozilla/layers/SharedSurfacesParent.h" 18 #include "mozilla/StaticPrefs_gfx.h" 19 #include "mozilla/StaticPrefs_webgl.h" 20 #include "mozilla/webgpu/WebGPUParent.h" 21 #include "nsIThread.h" 22 #include "nsThreadUtils.h" 23 24 namespace mozilla::gfx { 25 26 MOZ_RUNINIT CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers; 27 28 /* static */ void CanvasManagerParent::Init( 29 Endpoint<PCanvasManagerParent>&& aEndpoint, 30 layers::SharedSurfacesHolder* aSharedSurfacesHolder, 31 const dom::ContentParentId& aContentId) { 32 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); 33 34 auto manager = 35 MakeRefPtr<CanvasManagerParent>(aSharedSurfacesHolder, aContentId); 36 37 nsCOMPtr<nsIThread> owningThread = 38 gfx::CanvasRenderThread::GetCanvasRenderThread(); 39 MOZ_ASSERT(owningThread); 40 41 owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>( 42 "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, 43 std::move(aEndpoint))); 44 } 45 46 /* static */ void CanvasManagerParent::Shutdown() { 47 MOZ_ASSERT(NS_IsMainThread()); 48 49 nsCOMPtr<nsIThread> owningThread = 50 gfx::CanvasRenderThread::GetCanvasRenderThread(); 51 MOZ_ASSERT(owningThread); 52 53 NS_DispatchAndSpinEventLoopUntilComplete( 54 "CanvasManagerParent::Shutdown"_ns, owningThread, 55 NS_NewRunnableFunction("CanvasManagerParent::Shutdown", []() -> void { 56 CanvasManagerParent::ShutdownInternal(); 57 })); 58 } 59 60 /* static */ void CanvasManagerParent::ShutdownInternal() { 61 nsTArray<RefPtr<CanvasManagerParent>> actors(sManagers.Count()); 62 // Do a copy since Close will remove the entry from the set. 63 for (const auto& actor : sManagers) { 64 actors.AppendElement(actor); 65 } 66 67 for (auto const& actor : actors) { 68 actor->Close(); 69 } 70 } 71 72 /* static */ void CanvasManagerParent::DisableRemoteCanvas() { 73 NS_DispatchToMainThread( 74 NS_NewRunnableFunction("CanvasManagerParent::DisableRemoteCanvas", [] { 75 if (XRE_IsGPUProcess()) { 76 GPUParent::GetSingleton()->NotifyDisableRemoteCanvas(); 77 } else { 78 gfxPlatform::DisableRemoteCanvas(); 79 } 80 })); 81 82 if (CanvasRenderThread::IsInCanvasRenderThread()) { 83 DisableRemoteCanvasInternal(); 84 return; 85 } 86 87 CanvasRenderThread::Dispatch(NS_NewRunnableFunction( 88 "CanvasManagerParent::DisableRemoteCanvas", 89 [] { CanvasManagerParent::DisableRemoteCanvasInternal(); })); 90 } 91 92 /* static */ void CanvasManagerParent::DisableRemoteCanvasInternal() { 93 MOZ_ASSERT(CanvasRenderThread::IsInCanvasRenderThread()); 94 95 AutoTArray<RefPtr<layers::CanvasTranslator>, 16> actors; 96 for (const auto& manager : sManagers) { 97 for (const auto& canvas : manager->ManagedPCanvasParent()) { 98 actors.AppendElement(static_cast<layers::CanvasTranslator*>(canvas)); 99 } 100 } 101 102 for (const auto& actor : actors) { 103 (void)NS_WARN_IF(!actor->SendDeactivate()); 104 } 105 } 106 107 CanvasManagerParent::CanvasManagerParent( 108 layers::SharedSurfacesHolder* aSharedSurfacesHolder, 109 const dom::ContentParentId& aContentId) 110 : mSharedSurfacesHolder(aSharedSurfacesHolder), mContentId(aContentId) {} 111 112 CanvasManagerParent::~CanvasManagerParent() = default; 113 114 void CanvasManagerParent::Bind(Endpoint<PCanvasManagerParent>&& aEndpoint) { 115 if (!aEndpoint.Bind(this)) { 116 NS_WARNING("Failed to bind CanvasManagerParent!"); 117 return; 118 } 119 120 #ifdef DEBUG 121 for (CanvasManagerParent* i : sManagers) { 122 MOZ_ASSERT_IF(i->mContentId == mContentId, 123 i->OtherPidMaybeInvalid() == OtherPidMaybeInvalid()); 124 } 125 #endif 126 127 sManagers.Insert(this); 128 } 129 130 void CanvasManagerParent::ActorDestroy(ActorDestroyReason aWhy) { 131 sManagers.Remove(this); 132 } 133 134 already_AddRefed<dom::PWebGLParent> CanvasManagerParent::AllocPWebGLParent() { 135 if (NS_WARN_IF(!gfxVars::AllowWebglOop() && 136 !StaticPrefs::webgl_out_of_process_force())) { 137 MOZ_ASSERT_UNREACHABLE("AllocPWebGLParent without remote WebGL"); 138 return nullptr; 139 } 140 return MakeAndAddRef<dom::WebGLParent>(mSharedSurfacesHolder, mContentId); 141 } 142 143 already_AddRefed<webgpu::PWebGPUParent> 144 CanvasManagerParent::AllocPWebGPUParent() { 145 if (NS_WARN_IF(!gfxVars::AllowWebGPU())) { 146 MOZ_ASSERT_UNREACHABLE("AllocPWebGPUParent without WebGPU"); 147 return nullptr; 148 } 149 150 return MakeAndAddRef<webgpu::WebGPUParent>(mContentId); 151 } 152 153 mozilla::ipc::IPCResult CanvasManagerParent::RecvInitialize( 154 const uint32_t& aId) { 155 if (!aId) { 156 return IPC_FAIL(this, "invalid id"); 157 } 158 if (mId) { 159 return IPC_FAIL(this, "already initialized"); 160 } 161 mId = aId; 162 return IPC_OK(); 163 } 164 165 already_AddRefed<layers::PCanvasParent> 166 CanvasManagerParent::AllocPCanvasParent() { 167 if (NS_WARN_IF(!gfx::gfxVars::UseAcceleratedCanvas2D())) { 168 MOZ_ASSERT_UNREACHABLE("AllocPCanvasParent without remote canvas"); 169 return nullptr; 170 } 171 if (NS_WARN_IF(!mId)) { 172 MOZ_ASSERT_UNREACHABLE("AllocPCanvasParent without ID"); 173 return nullptr; 174 } 175 return MakeAndAddRef<layers::CanvasTranslator>(mSharedSurfacesHolder, 176 mContentId, mId); 177 } 178 179 mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot( 180 const uint32_t& aManagerId, const ActorId& aProtocolId, 181 const Maybe<RemoteTextureOwnerId>& aOwnerId, 182 const Maybe<RawId>& aCommandEncoderId, const Maybe<RawId>& aCommandBufferId, 183 webgl::FrontBufferSnapshotIpc* aResult) { 184 if (!aManagerId) { 185 return IPC_FAIL(this, "invalid id"); 186 } 187 188 IProtocol* actor = nullptr; 189 for (CanvasManagerParent* i : sManagers) { 190 if (i->mContentId == mContentId && i->mId == aManagerId) { 191 actor = i->Lookup(aProtocolId); 192 break; 193 } 194 } 195 196 if (!actor) { 197 return IPC_FAIL(this, "invalid actor"); 198 } 199 200 if (actor->GetSide() != mozilla::ipc::Side::ParentSide) { 201 return IPC_FAIL(this, "unsupported actor"); 202 } 203 204 webgl::FrontBufferSnapshotIpc buffer; 205 switch (actor->GetProtocolId()) { 206 case ProtocolId::PWebGLMsgStart: { 207 RefPtr<dom::WebGLParent> webgl = static_cast<dom::WebGLParent*>(actor); 208 mozilla::ipc::IPCResult rv = webgl->GetFrontBufferSnapshot(&buffer, this); 209 if (!rv) { 210 return rv; 211 } 212 } break; 213 case ProtocolId::PWebGPUMsgStart: { 214 RefPtr<webgpu::WebGPUParent> webgpu = 215 static_cast<webgpu::WebGPUParent*>(actor); 216 IntSize size; 217 if (aOwnerId.isNothing()) { 218 return IPC_FAIL(this, "invalid OwnerId"); 219 } 220 if (aCommandEncoderId.isNothing()) { 221 return IPC_FAIL(this, "invalid CommandEncoderId"); 222 } 223 if (aCommandBufferId.isNothing()) { 224 return IPC_FAIL(this, "invalid CommandBufferId"); 225 } 226 uint32_t stride = 0; 227 mozilla::ipc::IPCResult rv = webgpu->GetFrontBufferSnapshot( 228 this, *aOwnerId, *aCommandEncoderId, *aCommandBufferId, buffer.shmem, 229 size, stride); 230 if (!rv) { 231 return rv; 232 } 233 buffer.surfSize.x = static_cast<uint32_t>(size.width); 234 buffer.surfSize.y = static_cast<uint32_t>(size.height); 235 buffer.byteStride = stride; 236 } break; 237 default: 238 return IPC_FAIL(this, "unsupported protocol"); 239 } 240 241 *aResult = std::move(buffer); 242 return IPC_OK(); 243 } 244 245 /* static */ mozilla::ipc::IProtocol* CanvasManagerParent::GetCanvasActor( 246 dom::ContentParentId aContentId, uint32_t aManagerId, ActorId aCanvasId) { 247 IProtocol* actor = nullptr; 248 for (CanvasManagerParent* i : sManagers) { 249 if (i->mContentId == aContentId && i->mId == aManagerId) { 250 actor = i->Lookup(aCanvasId); 251 break; 252 } 253 } 254 return actor; 255 } 256 257 /* static */ already_AddRefed<SourceSurface> 258 CanvasManagerParent::GetCanvasSurface(dom::ContentParentId aContentId, 259 uint32_t aManagerId, ActorId aCanvasId, 260 uintptr_t aSurfaceId, 261 Maybe<layers::SurfaceDescriptor>* aDesc) { 262 IProtocol* actor = GetCanvasActor(aContentId, aManagerId, aCanvasId); 263 if (!actor) { 264 return nullptr; 265 } 266 switch (actor->GetProtocolId()) { 267 case ProtocolId::PCanvasMsgStart: 268 return static_cast<layers::CanvasTranslator*>(actor)->WaitForSurface( 269 aSurfaceId, aDesc); 270 default: 271 MOZ_ASSERT_UNREACHABLE("Unsupported protocol"); 272 break; 273 } 274 return nullptr; 275 } 276 277 } // namespace mozilla::gfx