WebGPUParent.cpp (64037B)
1 /* -*- Mode: C++; tab-width: 20; 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 "WebGPUParent.h" 7 8 #include <unordered_set> 9 10 #include "ExternalTexture.h" 11 #include "mozilla/ScopeExit.h" 12 #include "mozilla/dom/WebGPUBinding.h" 13 #include "mozilla/gfx/FileHandleWrapper.h" 14 #include "mozilla/gfx/gfxVars.h" 15 #include "mozilla/layers/CompositorThread.h" 16 #include "mozilla/layers/ImageDataSerializer.h" 17 #include "mozilla/layers/RemoteTextureMap.h" 18 #include "mozilla/layers/TextureHost.h" 19 #include "mozilla/layers/WebRenderImageHost.h" 20 #include "mozilla/layers/WebRenderTextureHost.h" 21 #include "mozilla/webgpu/SharedTexture.h" 22 #include "mozilla/webgpu/ffi/wgpu.h" 23 24 #if defined(XP_WIN) 25 # include "mozilla/gfx/DeviceManagerDx.h" 26 # include "mozilla/webgpu/SharedTextureD3D11.h" 27 #endif 28 29 #if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID) 30 # include "mozilla/webgpu/SharedTextureDMABuf.h" 31 #endif 32 33 #if defined(XP_MACOSX) 34 # include "mozilla/webgpu/SharedTextureMacIOSurface.h" 35 #endif 36 37 namespace mozilla::webgpu { 38 39 const uint64_t POLL_TIME_MS = 100; 40 41 static mozilla::LazyLogModule sLogger("WebGPU"); 42 43 namespace ffi { 44 45 extern bool wgpu_server_use_shared_texture_for_swap_chain( 46 WGPUWebGPUParentPtr aParent, WGPUSwapChainId aSwapChainId) { 47 auto* parent = static_cast<WebGPUParent*>(aParent); 48 49 return parent->UseSharedTextureForSwapChain(aSwapChainId); 50 } 51 52 extern void wgpu_server_disable_shared_texture_for_swap_chain( 53 WGPUWebGPUParentPtr aParent, WGPUSwapChainId aSwapChainId) { 54 auto* parent = static_cast<WebGPUParent*>(aParent); 55 56 parent->DisableSharedTextureForSwapChain(aSwapChainId); 57 } 58 59 extern bool wgpu_server_ensure_shared_texture_for_swap_chain( 60 WGPUWebGPUParentPtr aParent, WGPUSwapChainId aSwapChainId, 61 WGPUDeviceId aDeviceId, WGPUTextureId aTextureId, uint32_t aWidth, 62 uint32_t aHeight, struct WGPUTextureFormat aFormat, 63 WGPUTextureUsages aUsage) { 64 auto* parent = static_cast<WebGPUParent*>(aParent); 65 66 return parent->EnsureSharedTextureForSwapChain( 67 aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage); 68 } 69 70 extern void wgpu_server_ensure_shared_texture_for_readback( 71 WGPUWebGPUParentPtr aParent, WGPUSwapChainId aSwapChainId, 72 WGPUDeviceId aDeviceId, WGPUTextureId aTextureId, uint32_t aWidth, 73 uint32_t aHeight, struct WGPUTextureFormat aFormat, 74 WGPUTextureUsages aUsage) { 75 auto* parent = static_cast<WebGPUParent*>(aParent); 76 77 parent->EnsureSharedTextureForReadBackPresent( 78 aSwapChainId, aDeviceId, aTextureId, aWidth, aHeight, aFormat, aUsage); 79 } 80 81 #ifdef XP_WIN 82 extern void* wgpu_server_get_shared_texture_handle(WGPUWebGPUParentPtr aParent, 83 WGPUTextureId aId) { 84 auto* parent = static_cast<WebGPUParent*>(aParent); 85 86 auto texture = parent->GetSharedTexture(aId); 87 if (!texture) { 88 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 89 return nullptr; 90 } 91 92 auto* textureD3D11 = texture->AsSharedTextureD3D11(); 93 if (!textureD3D11) { 94 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 95 return nullptr; 96 } 97 void* sharedHandle = textureD3D11->GetSharedTextureHandle(); 98 if (!sharedHandle) { 99 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 100 gfxCriticalNoteOnce << "Failed to get shared handle"; 101 return nullptr; 102 } 103 104 return sharedHandle; 105 } 106 #endif 107 108 #if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID) 109 extern int32_t wgpu_server_get_dma_buf_fd(WGPUWebGPUParentPtr aParent, 110 WGPUTextureId aId) { 111 auto* parent = static_cast<WebGPUParent*>(aParent); 112 113 auto texture = parent->GetSharedTexture(aId); 114 if (!texture) { 115 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 116 return -1; 117 } 118 119 auto* textureDMABuf = texture->AsSharedTextureDMABuf(); 120 if (!textureDMABuf) { 121 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 122 return -1; 123 } 124 auto fd = textureDMABuf->CloneDmaBufFd(); 125 // fd should be closed by the caller. 126 return fd.release(); 127 } 128 #endif 129 130 #if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID) 131 extern const WGPUVkImageHandle* wgpu_server_get_vk_image_handle( 132 WGPUWebGPUParentPtr aParent, WGPUTextureId aId) { 133 auto* parent = static_cast<WebGPUParent*>(aParent); 134 135 auto texture = parent->GetSharedTexture(aId); 136 if (!texture) { 137 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 138 return nullptr; 139 } 140 141 auto* textureDMABuf = texture->AsSharedTextureDMABuf(); 142 if (!textureDMABuf) { 143 return nullptr; 144 } 145 return textureDMABuf->GetHandle(); 146 } 147 #endif 148 149 #if defined(XP_MACOSX) 150 extern uint32_t wgpu_server_get_external_io_surface_id( 151 WGPUWebGPUParentPtr aParent, WGPUTextureId aId) { 152 auto* parent = static_cast<WebGPUParent*>(aParent); 153 154 auto texture = parent->GetSharedTexture(aId); 155 if (!texture) { 156 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 157 return 0; 158 } 159 160 auto* textureIOSurface = texture->AsSharedTextureMacIOSurface(); 161 if (!textureIOSurface) { 162 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 163 return 0; 164 } 165 return textureIOSurface->GetIOSurfaceId(); 166 } 167 #endif 168 169 extern void wgpu_server_remove_shared_texture(WGPUWebGPUParentPtr aParent, 170 WGPUTextureId aId) { 171 auto* parent = static_cast<WebGPUParent*>(aParent); 172 parent->RemoveSharedTexture(aId); 173 } 174 175 extern bool wgpu_parent_is_external_texture_enabled() { 176 return gfx::gfxVars::AllowWebGPUExternalTexture(); 177 } 178 179 extern ffi::WGPUExternalTextureDescriptorFromSource 180 wgpu_parent_external_texture_source_get_external_texture_descriptor( 181 void* aParent, WGPUExternalTextureSourceId aId, 182 ffi::WGPUPredefinedColorSpace aDestColorSpace) { 183 auto* parent = static_cast<WebGPUParent*>(aParent); 184 const auto& source = parent->GetExternalTextureSource(aId); 185 return source.GetExternalTextureDescriptor(aDestColorSpace); 186 } 187 188 extern void wgpu_parent_destroy_external_texture_source( 189 WGPUWebGPUParentPtr aParent, WGPUExternalTextureSourceId aId) { 190 auto* const parent = static_cast<WebGPUParent*>(aParent); 191 parent->DestroyExternalTextureSource(aId); 192 } 193 194 extern void wgpu_parent_drop_external_texture_source( 195 WGPUWebGPUParentPtr aParent, WGPUExternalTextureSourceId aId) { 196 auto* const parent = static_cast<WebGPUParent*>(aParent); 197 parent->DropExternalTextureSource(aId); 198 } 199 200 extern void wgpu_server_dealloc_buffer_shmem(WGPUWebGPUParentPtr aParent, 201 WGPUBufferId aId) { 202 auto* parent = static_cast<WebGPUParent*>(aParent); 203 parent->DeallocBufferShmem(aId); 204 } 205 206 extern void wgpu_server_pre_device_drop(WGPUWebGPUParentPtr aParent, 207 WGPUDeviceId aId) { 208 auto* parent = static_cast<WebGPUParent*>(aParent); 209 parent->PreDeviceDrop(aId); 210 } 211 212 extern void wgpu_server_set_buffer_map_data( 213 WGPUWebGPUParentPtr aParent, WGPUDeviceId aDeviceId, WGPUBufferId aBufferId, 214 bool aHasMapFlags, uint64_t aMappedOffset, uint64_t aMappedSize, 215 uintptr_t aShmemIndex) { 216 auto* parent = static_cast<WebGPUParent*>(aParent); 217 218 auto mapping = parent->mTempMappings.at(aShmemIndex); 219 220 auto data = WebGPUParent::BufferMapData{ 221 mapping, aHasMapFlags, aMappedOffset, aMappedSize, aDeviceId, 222 }; 223 224 parent->mSharedMemoryMap.insert({aBufferId, std::move(data)}); 225 } 226 227 extern void wgpu_server_device_push_error_scope(WGPUWebGPUParentPtr aParent, 228 WGPUDeviceId aDeviceId, 229 uint8_t aFilter) { 230 auto* parent = static_cast<WebGPUParent*>(aParent); 231 parent->DevicePushErrorScope(aDeviceId, (dom::GPUErrorFilter)aFilter); 232 } 233 234 extern void wgpu_server_device_pop_error_scope(WGPUWebGPUParentPtr aParent, 235 WGPUDeviceId aDeviceId, 236 uint8_t* aOutType, 237 nsCString* aOutMessage) { 238 auto* parent = static_cast<WebGPUParent*>(aParent); 239 auto result = parent->DevicePopErrorScope(aDeviceId); 240 *aOutType = (uint8_t)result.resultType; 241 *aOutMessage = std::move(result.message); 242 } 243 244 extern void wgpu_parent_buffer_unmap(WGPUWebGPUParentPtr aParent, 245 WGPUDeviceId aDeviceId, 246 WGPUBufferId aBufferId, bool aFlush) { 247 auto* parent = static_cast<WebGPUParent*>(aParent); 248 parent->BufferUnmap(aDeviceId, aBufferId, aFlush); 249 } 250 251 extern void wgpu_parent_queue_submit( 252 WGPUWebGPUParentPtr aParent, WGPUDeviceId aDeviceId, WGPUQueueId aQueueId, 253 const WGPUCommandBufferId* aCommandBufferIds, 254 uintptr_t aCommandBufferIdsLength, const WGPUTextureId* aTextureIds, 255 uintptr_t aTextureIdsLength, 256 const WGPUExternalTextureSourceId* aExternalTextureSourceIds, 257 uintptr_t aExternalTextureSourceIdsLength) { 258 auto* parent = static_cast<WebGPUParent*>(aParent); 259 auto command_buffers = Span(aCommandBufferIds, aCommandBufferIdsLength); 260 auto textures = Span(aTextureIds, aTextureIdsLength); 261 auto externalTextureSources = 262 Span(aExternalTextureSourceIds, aExternalTextureSourceIdsLength); 263 parent->QueueSubmit(aQueueId, aDeviceId, command_buffers, textures, 264 externalTextureSources); 265 } 266 267 extern void wgpu_parent_create_swap_chain( 268 WGPUWebGPUParentPtr aParent, WGPUDeviceId aDeviceId, WGPUQueueId aQueueId, 269 int32_t aWidth, int32_t aHeight, WGPUSurfaceFormat aFormat, 270 const WGPUBufferId* aBufferIds, uintptr_t aBufferIdsLength, 271 WGPURemoteTextureOwnerId aRemoteTextureOwnerId, 272 bool aUseSharedTextureInSwapChain) { 273 auto* parent = static_cast<WebGPUParent*>(aParent); 274 auto buffer_ids_span = Span(aBufferIds, aBufferIdsLength); 275 auto buffer_ids = nsTArray<RawId>(aBufferIdsLength); 276 for (const RawId id : buffer_ids_span) { 277 buffer_ids.AppendElement(id); 278 } 279 auto size = gfx::IntSize(aWidth, aHeight); 280 auto format = gfx::SurfaceFormat(aFormat); 281 auto desc = layers::RGBDescriptor(size, format); 282 auto owner = layers::RemoteTextureOwnerId{aRemoteTextureOwnerId}; 283 parent->DeviceCreateSwapChain(aDeviceId, aQueueId, desc, buffer_ids, owner, 284 aUseSharedTextureInSwapChain); 285 } 286 287 extern void wgpu_parent_swap_chain_present( 288 WGPUWebGPUParentPtr aParent, WGPUTextureId aTextureId, 289 WGPUCommandEncoderId aCommandEncoderId, 290 WGPUCommandBufferId aCommandBufferId, WGPURemoteTextureId aRemoteTextureId, 291 WGPURemoteTextureOwnerId aRemoteTextureOwnerId) { 292 auto* parent = static_cast<WebGPUParent*>(aParent); 293 auto remote_texture = layers::RemoteTextureId{aRemoteTextureId}; 294 auto owner = layers::RemoteTextureOwnerId{aRemoteTextureOwnerId}; 295 parent->SwapChainPresent(aTextureId, aCommandEncoderId, aCommandBufferId, 296 remote_texture, owner); 297 } 298 299 extern void wgpu_parent_swap_chain_drop( 300 WGPUWebGPUParentPtr aParent, WGPURemoteTextureOwnerId aRemoteTextureOwnerId, 301 WGPURemoteTextureTxnType aTxnType, WGPURemoteTextureTxnId aTxnId) { 302 auto* parent = static_cast<WebGPUParent*>(aParent); 303 auto owner = layers::RemoteTextureOwnerId{aRemoteTextureOwnerId}; 304 parent->SwapChainDrop(owner, aTxnType, aTxnId); 305 } 306 307 #ifdef XP_WIN 308 extern void wgpu_parent_get_compositor_device_luid( 309 struct WGPUFfiLUID* aOutLuid) { 310 auto luid = WebGPUParent::GetCompositorDeviceLuid(); 311 if (luid.isSome()) { 312 *aOutLuid = luid.extract(); 313 } else { 314 aOutLuid = nullptr; 315 } 316 } 317 #endif 318 319 extern void wgpu_parent_post_request_device(WGPUWebGPUParentPtr aParent, 320 WGPUDeviceId aDeviceId) { 321 auto* parent = static_cast<WebGPUParent*>(aParent); 322 parent->PostAdapterRequestDevice(aDeviceId); 323 } 324 325 extern ffi::WGPUBufferMapClosure wgpu_parent_build_buffer_map_closure( 326 WGPUWebGPUParentPtr aParent, RawId aDeviceId, RawId aBufferId, 327 ffi::WGPUHostMap aMode, uint64_t aOffset, uint64_t aSize) { 328 auto* parent = static_cast<WebGPUParent*>(aParent); 329 330 std::unique_ptr<WebGPUParent::MapRequest> request( 331 new WebGPUParent::MapRequest{parent, aDeviceId, aBufferId, aMode, aOffset, 332 aSize}); 333 334 ffi::WGPUBufferMapClosure closure = { 335 &WebGPUParent::MapCallback, 336 reinterpret_cast<uint8_t*>(request.release())}; 337 338 return closure; 339 } 340 341 extern ffi::WGPUSubmittedWorkDoneClosure 342 wgpu_parent_build_submitted_work_done_closure(WGPUWebGPUParentPtr aParent, 343 WGPUQueueId aQueueId) { 344 auto* parent = static_cast<WebGPUParent*>(aParent); 345 346 std::unique_ptr<WebGPUParent::OnSubmittedWorkDoneRequest> request( 347 new WebGPUParent::OnSubmittedWorkDoneRequest{parent, aQueueId}); 348 349 ffi::WGPUSubmittedWorkDoneClosure closure = { 350 &WebGPUParent::OnSubmittedWorkDoneCallback, 351 reinterpret_cast<uint8_t*>(request.release())}; 352 353 return closure; 354 } 355 356 extern void wgpu_parent_handle_error(WGPUWebGPUParentPtr aParent, 357 WGPUDeviceId aDeviceId, 358 WGPUErrorBufferType aTy, 359 const nsCString* aMessage) { 360 auto* parent = static_cast<WebGPUParent*>(aParent); 361 362 dom::GPUErrorFilter ty; 363 switch (aTy) { 364 case ffi::WGPUErrorBufferType_Internal: 365 ty = dom::GPUErrorFilter::Internal; 366 break; 367 case ffi::WGPUErrorBufferType_Validation: 368 ty = dom::GPUErrorFilter::Validation; 369 break; 370 case ffi::WGPUErrorBufferType_OutOfMemory: 371 ty = dom::GPUErrorFilter::Out_of_memory; 372 break; 373 default: 374 MOZ_CRASH("invalid `ErrorBufferType`"); 375 } 376 377 parent->ReportError(aDeviceId, ty, *aMessage); 378 } 379 380 extern void wgpu_parent_send_server_message(WGPUWebGPUParentPtr aParent, 381 struct WGPUByteBuf* aMessage) { 382 auto* parent = static_cast<WebGPUParent*>(aParent); 383 auto* message = FromFFI(aMessage); 384 if (!parent->SendServerMessage(std::move(*message))) { 385 NS_ERROR("SendServerMessage failed"); 386 } 387 } 388 389 } // namespace ffi 390 391 ErrorBuffer::ErrorBuffer() { mMessageUtf8[0] = 0; } 392 393 ErrorBuffer::~ErrorBuffer() { MOZ_ASSERT(!mAwaitingGetError); } 394 395 ffi::WGPUErrorBuffer ErrorBuffer::ToFFI() { 396 mAwaitingGetError = true; 397 ffi::WGPUErrorBuffer errorBuf = {&mType, mMessageUtf8, BUFFER_SIZE, 398 &mDeviceId}; 399 return errorBuf; 400 } 401 402 ffi::WGPUErrorBufferType ErrorBuffer::GetType() { return mType; } 403 404 Maybe<dom::GPUErrorFilter> ErrorBuffer::ErrorTypeToFilterType( 405 ffi::WGPUErrorBufferType aType) { 406 switch (aType) { 407 case ffi::WGPUErrorBufferType_None: 408 case ffi::WGPUErrorBufferType_DeviceLost: 409 return {}; 410 case ffi::WGPUErrorBufferType_Internal: 411 return Some(dom::GPUErrorFilter::Internal); 412 case ffi::WGPUErrorBufferType_Validation: 413 return Some(dom::GPUErrorFilter::Validation); 414 case ffi::WGPUErrorBufferType_OutOfMemory: 415 return Some(dom::GPUErrorFilter::Out_of_memory); 416 case ffi::WGPUErrorBufferType_Sentinel: 417 break; 418 } 419 420 MOZ_CRASH("invalid `ErrorBufferType`"); 421 } 422 423 Maybe<ErrorBuffer::Error> ErrorBuffer::GetError() { 424 mAwaitingGetError = false; 425 if (mType == ffi::WGPUErrorBufferType_DeviceLost) { 426 // This error is for a lost device, so we return an Error struct 427 // with the isDeviceLost bool set to true. It doesn't matter what 428 // GPUErrorFilter type we use, so we just use Validation. The error 429 // will not be reported. 430 return Some(Error{dom::GPUErrorFilter::Validation, true, 431 nsCString{mMessageUtf8}, mDeviceId}); 432 } 433 auto filterType = ErrorTypeToFilterType(mType); 434 if (!filterType) { 435 return {}; 436 } 437 return Some(Error{*filterType, false, nsCString{mMessageUtf8}, mDeviceId}); 438 } 439 440 void ErrorBuffer::CoerceValidationToInternal() { 441 if (mType == ffi::WGPUErrorBufferType_Validation) { 442 mType = ffi::WGPUErrorBufferType_Internal; 443 } 444 } 445 446 struct PendingSwapChainDrop { 447 layers::RemoteTextureTxnType mTxnType; 448 layers::RemoteTextureTxnId mTxnId; 449 }; 450 451 class PresentationData { 452 NS_INLINE_DECL_REFCOUNTING(PresentationData); 453 454 public: 455 WeakPtr<WebGPUParent> mParent; 456 bool mUseSharedTextureInSwapChain; 457 const RawId mDeviceId; 458 const RawId mQueueId; 459 Maybe<RawId> mLastSubmittedTextureId; 460 const layers::RGBDescriptor mDesc; 461 462 uint64_t mSubmissionIndex = 0; 463 464 std::deque<std::shared_ptr<SharedTexture>> mRecycledSharedTextures; 465 466 std::unordered_set<layers::RemoteTextureId, layers::RemoteTextureId::HashFn> 467 mWaitingReadbackTexturesForPresent; 468 Maybe<PendingSwapChainDrop> mPendingSwapChainDrop; 469 470 const uint32_t mSourcePitch; 471 std::vector<RawId> mUnassignedBufferIds; 472 std::vector<RawId> mAvailableBufferIds; 473 std::vector<RawId> mQueuedBufferIds; 474 475 bool mReadbackSnapshotCallbackCalled = false; 476 477 PresentationData(WebGPUParent* aParent, bool aUseSharedTextureInSwapChain, 478 RawId aDeviceId, RawId aQueueId, 479 const layers::RGBDescriptor& aDesc, uint32_t aSourcePitch, 480 const nsTArray<RawId>& aBufferIds) 481 : mParent(aParent), 482 mUseSharedTextureInSwapChain(aUseSharedTextureInSwapChain), 483 mDeviceId(aDeviceId), 484 mQueueId(aQueueId), 485 mDesc(aDesc), 486 mSourcePitch(aSourcePitch) { 487 MOZ_COUNT_CTOR(PresentationData); 488 489 for (const RawId id : aBufferIds) { 490 mUnassignedBufferIds.push_back(id); 491 } 492 } 493 494 private: 495 ~PresentationData() { MOZ_COUNT_DTOR(PresentationData); } 496 }; 497 498 WebGPUParent::WebGPUParent(const dom::ContentParentId& aContentId) 499 : mContentId(aContentId), mContext(ffi::wgpu_server_new(this)) { 500 mTimer.Start(base::TimeDelta::FromMilliseconds(POLL_TIME_MS), this, 501 &WebGPUParent::MaintainDevices); 502 } 503 504 WebGPUParent::~WebGPUParent() = default; 505 506 void WebGPUParent::MaintainDevices() { 507 ffi::wgpu_server_poll_all_devices(mContext.get(), false); 508 } 509 510 void WebGPUParent::LoseDevice(const RawId aDeviceId, uint8_t aReason, 511 const nsACString& aMessage) { 512 if (mActiveDeviceIds.Contains(aDeviceId)) { 513 mActiveDeviceIds.Remove(aDeviceId); 514 } 515 // Check to see if we've already sent a DeviceLost message to aDeviceId. 516 if (mLostDeviceIds.Contains(aDeviceId)) { 517 return; 518 } 519 520 // If the connection has been dropped, there is nobody to receive 521 // the DeviceLost message anyway. 522 if (!CanSend()) { 523 return; 524 } 525 526 if (!SendDeviceLost(aDeviceId, aReason, aMessage)) { 527 NS_ERROR("SendDeviceLost failed"); 528 return; 529 } 530 531 mLostDeviceIds.Insert(aDeviceId); 532 } 533 534 bool WebGPUParent::ForwardError(ErrorBuffer& aError) { 535 if (auto error = aError.GetError()) { 536 // If this is a error has isDeviceLost true, then instead of reporting 537 // the error, we swallow it and call LoseDevice if we have an 538 // aDeviceID. This is to comply with the spec declaration in 539 // https://gpuweb.github.io/gpuweb/#lose-the-device 540 // "No errors are generated after device loss." 541 if (error->isDeviceLost) { 542 if (error->deviceId) { 543 LoseDevice(error->deviceId, 544 static_cast<uint8_t>(dom::GPUDeviceLostReason::Unknown), 545 error->message); 546 } 547 } else { 548 ReportError(error->deviceId, error->type, error->message); 549 } 550 return true; 551 } 552 return false; 553 } 554 555 // Generate an error on the Device timeline of aDeviceId. 556 // aMessage is interpreted as UTF-8. 557 void WebGPUParent::ReportError(RawId aDeviceId, const GPUErrorFilter aType, 558 const nsCString& aMessage) { 559 // find the appropriate error scope 560 if (aDeviceId) { 561 const auto& itr = mErrorScopeStackByDevice.find(aDeviceId); 562 if (itr != mErrorScopeStackByDevice.end()) { 563 auto& stack = itr->second; 564 for (auto& scope : Reversed(stack)) { 565 if (scope.filter != aType) { 566 continue; 567 } 568 if (!scope.firstMessage) { 569 scope.firstMessage = Some(aMessage); 570 } 571 return; 572 } 573 } 574 } 575 // No error scope found, so fall back to the uncaptured error handler 576 if (!SendUncapturedError(aDeviceId, aMessage)) { 577 NS_ERROR("SendDeviceUncapturedError failed"); 578 } 579 } 580 581 struct OnDeviceLostRequest { 582 WeakPtr<WebGPUParent> mParent; 583 RawId mDeviceId; 584 }; 585 586 static void DeviceLostCleanupCallback(uint8_t* aUserData) { 587 auto req = std::unique_ptr<OnDeviceLostRequest>( 588 reinterpret_cast<OnDeviceLostRequest*>(aUserData)); 589 } 590 591 /* static */ void WebGPUParent::DeviceLostCallback(uint8_t* aUserData, 592 uint8_t aReason, 593 const char* aMessage) { 594 auto req = std::unique_ptr<OnDeviceLostRequest>( 595 reinterpret_cast<OnDeviceLostRequest*>(aUserData)); 596 if (!req->mParent) { 597 // Parent is dead, never mind. 598 return; 599 } 600 601 RawId deviceId = req->mDeviceId; 602 603 // NOTE: Based on `u8` discriminant values provided for `DeviceLostReason` in 604 // `wgpu_bindings`. 605 uint8_t reason; 606 switch (aReason) { 607 case 0: 608 reason = static_cast<uint8_t>(dom::GPUDeviceLostReason::Unknown); 609 break; 610 case 1: 611 reason = static_cast<uint8_t>(dom::GPUDeviceLostReason::Destroyed); 612 break; 613 default: 614 MOZ_CRASH_UNSAFE_PRINTF( 615 "invalid `aReason` from device lost callback: %hhu", aReason); 616 break; 617 } 618 nsAutoCString message(aMessage); 619 req->mParent->LoseDevice(deviceId, reason, message); 620 621 auto it = req->mParent->mDeviceFenceHandles.find(deviceId); 622 if (it != req->mParent->mDeviceFenceHandles.end()) { 623 req->mParent->mDeviceFenceHandles.erase(it); 624 } 625 } 626 627 void WebGPUParent::PostAdapterRequestDevice(RawId aDeviceId) { 628 mErrorScopeStackByDevice.insert({aDeviceId, {}}); 629 630 std::unique_ptr<OnDeviceLostRequest> request( 631 new OnDeviceLostRequest{this, aDeviceId}); 632 ffi::WGPUDeviceLostClosure closure = { 633 &DeviceLostCallback, &DeviceLostCleanupCallback, 634 reinterpret_cast<uint8_t*>(request.release())}; 635 ffi::wgpu_server_set_device_lost_callback(mContext.get(), aDeviceId, closure); 636 637 #if defined(XP_WIN) 638 HANDLE handle = 639 wgpu_server_get_device_fence_handle(mContext.get(), aDeviceId); 640 if (handle) { 641 RefPtr<gfx::FileHandleWrapper> fenceHandle = 642 new gfx::FileHandleWrapper(UniqueFileHandle(handle)); 643 mDeviceFenceHandles.emplace(aDeviceId, std::move(fenceHandle)); 644 } 645 #endif 646 647 MOZ_ASSERT(!mActiveDeviceIds.Contains(aDeviceId)); 648 mActiveDeviceIds.Insert(aDeviceId); 649 } 650 651 void WebGPUParent::PreDeviceDrop(RawId aDeviceId) { 652 if (mActiveDeviceIds.Contains(aDeviceId)) { 653 mActiveDeviceIds.Remove(aDeviceId); 654 } 655 mErrorScopeStackByDevice.erase(aDeviceId); 656 mLostDeviceIds.Remove(aDeviceId); 657 } 658 659 WebGPUParent::BufferMapData* WebGPUParent::GetBufferMapData(RawId aBufferId) { 660 const auto iter = mSharedMemoryMap.find(aBufferId); 661 if (iter == mSharedMemoryMap.end()) { 662 return nullptr; 663 } 664 665 return &iter->second; 666 } 667 668 static const char* MapStatusString(ffi::WGPUBufferMapAsyncStatus status) { 669 switch (status) { 670 case ffi::WGPUBufferMapAsyncStatus_Success: 671 return "Success"; 672 case ffi::WGPUBufferMapAsyncStatus_AlreadyMapped: 673 return "Already mapped"; 674 case ffi::WGPUBufferMapAsyncStatus_MapAlreadyPending: 675 return "Map is already pending"; 676 case ffi::WGPUBufferMapAsyncStatus_ContextLost: 677 return "Context lost"; 678 case ffi::WGPUBufferMapAsyncStatus_Invalid: 679 return "Invalid buffer"; 680 case ffi::WGPUBufferMapAsyncStatus_InvalidRange: 681 return "Invalid range"; 682 case ffi::WGPUBufferMapAsyncStatus_InvalidAlignment: 683 return "Invalid alignment"; 684 case ffi::WGPUBufferMapAsyncStatus_InvalidUsageFlags: 685 return "Invalid usage flags"; 686 case ffi::WGPUBufferMapAsyncStatus_Error: 687 return "Map failed"; 688 case ffi::WGPUBufferMapAsyncStatus_Sentinel: // For -Wswitch 689 break; 690 } 691 692 MOZ_CRASH("Bad ffi::WGPUBufferMapAsyncStatus"); 693 } 694 695 void WebGPUParent::MapCallback(uint8_t* aUserData, 696 ffi::WGPUBufferMapAsyncStatus aStatus) { 697 auto req = 698 std::unique_ptr<MapRequest>(reinterpret_cast<MapRequest*>(aUserData)); 699 700 if (!req->mParent) { 701 return; 702 } 703 if (!req->mParent->CanSend()) { 704 return; 705 } 706 707 ipc::ByteBuf bb; 708 709 if (aStatus != ffi::WGPUBufferMapAsyncStatus_Success) { 710 // A buffer map operation that fails with a DeviceError gets 711 // mapped to the ContextLost status. If we have this status, we 712 // need to lose the device. 713 if (aStatus == ffi::WGPUBufferMapAsyncStatus_ContextLost) { 714 req->mParent->LoseDevice( 715 req->mDeviceId, 716 static_cast<uint8_t>(dom::GPUDeviceLostReason::Unknown), 717 nsPrintfCString("Buffer %" PRIu64 " invalid", req->mBufferId)); 718 } 719 auto error = nsPrintfCString("Mapping WebGPU buffer failed: %s", 720 MapStatusString(aStatus)); 721 722 ffi::wgpu_server_pack_buffer_map_error(req->mBufferId, &error, ToFFI(&bb)); 723 } else { 724 auto* mapData = req->mParent->GetBufferMapData(req->mBufferId); 725 MOZ_RELEASE_ASSERT(mapData); 726 727 auto size = req->mSize; 728 auto offset = req->mOffset; 729 730 if (req->mHostMap == ffi::WGPUHostMap_Read && size > 0) { 731 ErrorBuffer error; 732 const auto src = ffi::wgpu_server_buffer_get_mapped_range( 733 req->mParent->GetContext(), mapData->mDeviceId, req->mBufferId, 734 offset, size, error.ToFFI()); 735 736 MOZ_RELEASE_ASSERT(!error.GetError()); 737 738 MOZ_RELEASE_ASSERT(mapData->mShmem->Size() >= offset + size); 739 if (src.ptr != nullptr && src.length >= size) { 740 auto dst = mapData->mShmem->DataAsSpan<uint8_t>().Subspan(offset, size); 741 memcpy(dst.data(), src.ptr, size); 742 } 743 } 744 745 bool is_writable = req->mHostMap == ffi::WGPUHostMap_Write; 746 ffi::wgpu_server_pack_buffer_map_success(req->mBufferId, is_writable, 747 offset, size, ToFFI(&bb)); 748 749 mapData->mMappedOffset = offset; 750 mapData->mMappedSize = size; 751 } 752 753 if (!req->mParent->SendServerMessage(std::move(bb))) { 754 NS_ERROR("SendServerMessage failed"); 755 } 756 } 757 758 void WebGPUParent::BufferUnmap(RawId aDeviceId, RawId aBufferId, bool aFlush) { 759 MOZ_LOG(sLogger, LogLevel::Info, 760 ("RecvBufferUnmap %" PRIu64 " flush=%d\n", aBufferId, aFlush)); 761 762 auto* mapData = GetBufferMapData(aBufferId); 763 764 if (mapData && aFlush) { 765 uint64_t offset = mapData->mMappedOffset; 766 uint64_t size = mapData->mMappedSize; 767 768 ErrorBuffer getRangeError; 769 const auto mapped = ffi::wgpu_server_buffer_get_mapped_range( 770 mContext.get(), aDeviceId, aBufferId, offset, size, 771 getRangeError.ToFFI()); 772 ForwardError(getRangeError); 773 774 if (mapped.ptr != nullptr && mapped.length >= size) { 775 auto shmSize = mapData->mShmem->Size(); 776 MOZ_RELEASE_ASSERT(offset <= shmSize); 777 MOZ_RELEASE_ASSERT(size <= shmSize - offset); 778 779 auto src = mapData->mShmem->DataAsSpan<uint8_t>().Subspan(offset, size); 780 memcpy(mapped.ptr, src.data(), size); 781 } 782 783 mapData->mMappedOffset = 0; 784 mapData->mMappedSize = 0; 785 } 786 787 ErrorBuffer unmapError; 788 ffi::wgpu_server_buffer_unmap(mContext.get(), aDeviceId, aBufferId, 789 unmapError.ToFFI()); 790 ForwardError(unmapError); 791 792 if (mapData && !mapData->mHasMapFlags) { 793 // We get here if the buffer was mapped at creation without map flags. 794 // We don't need the shared memory anymore. 795 DeallocBufferShmem(aBufferId); 796 } 797 } 798 799 void WebGPUParent::DeallocBufferShmem(RawId aBufferId) { 800 const auto iter = mSharedMemoryMap.find(aBufferId); 801 if (iter != mSharedMemoryMap.end()) { 802 mSharedMemoryMap.erase(iter); 803 } 804 } 805 806 void WebGPUParent::RemoveSharedTexture(RawId aTextureId) { 807 auto it = mSharedTextures.find(aTextureId); 808 if (it != mSharedTextures.end()) { 809 mSharedTextures.erase(it); 810 } 811 } 812 813 const ExternalTextureSourceHost& WebGPUParent::GetExternalTextureSource( 814 ffi::WGPUExternalTextureSourceId aId) const { 815 return mExternalTextureSources.at(aId); 816 } 817 818 void WebGPUParent::DestroyExternalTextureSource(RawId aSourceId) { 819 auto it = mExternalTextureSources.find(aSourceId); 820 if (it != mExternalTextureSources.end()) { 821 for (const auto textureId : it->second.TextureIds()) { 822 ffi::wgpu_server_texture_destroy(mContext.get(), textureId); 823 } 824 } 825 } 826 827 void WebGPUParent::DropExternalTextureSource(RawId aSourceId) { 828 auto it = mExternalTextureSources.find(aSourceId); 829 if (it != mExternalTextureSources.end()) { 830 for (const auto viewId : it->second.ViewIds()) { 831 ffi::wgpu_server_texture_view_drop(mContext.get(), viewId); 832 } 833 for (const auto textureId : it->second.TextureIds()) { 834 ffi::wgpu_server_texture_drop(mContext.get(), textureId); 835 } 836 mExternalTextureSources.erase(it); 837 } 838 } 839 840 void WebGPUParent::QueueSubmit(RawId aQueueId, RawId aDeviceId, 841 Span<const RawId> aCommandBuffers, 842 Span<const RawId> aTextureIds, 843 Span<const RawId> aExternalTextureSourceIds) { 844 for (const auto& textureId : aTextureIds) { 845 auto it = mSharedTextures.find(textureId); 846 if (it != mSharedTextures.end()) { 847 auto& sharedTexture = it->second; 848 sharedTexture->onBeforeQueueSubmit(aQueueId); 849 } 850 } 851 852 for (const auto& sourceId : aExternalTextureSourceIds) { 853 auto it = mExternalTextureSources.find(sourceId); 854 if (it != mExternalTextureSources.end()) { 855 auto& source = it->second; 856 if (!source.OnBeforeQueueSubmit(this, aDeviceId, aQueueId)) { 857 // If the above call failed we cannot submit the command buffers, as 858 // it would be invalid to read from the external textures. 859 return; 860 } 861 } 862 } 863 864 ErrorBuffer error; 865 auto index = ffi::wgpu_server_queue_submit( 866 mContext.get(), aDeviceId, aQueueId, 867 {aCommandBuffers.Elements(), aCommandBuffers.Length()}, error.ToFFI()); 868 // Check if index is valid. 0 means error. 869 if (index != 0) { 870 for (const auto& textureId : aTextureIds) { 871 auto it = mSharedTextures.find(textureId); 872 if (it != mSharedTextures.end()) { 873 auto& sharedTexture = it->second; 874 875 sharedTexture->SetSubmissionIndex(index); 876 // Update mLastSubmittedTextureId 877 auto ownerId = sharedTexture->GetOwnerId(); 878 const auto& lookup = mPresentationDataMap.find(ownerId); 879 if (lookup != mPresentationDataMap.end()) { 880 RefPtr<PresentationData> data = lookup->second.get(); 881 data->mLastSubmittedTextureId = Some(textureId); 882 } 883 } 884 } 885 } 886 ForwardError(error); 887 } 888 889 void WebGPUParent::OnSubmittedWorkDoneCallback(uint8_t* userdata) { 890 auto req = std::unique_ptr<OnSubmittedWorkDoneRequest>( 891 reinterpret_cast<OnSubmittedWorkDoneRequest*>(userdata)); 892 if (!req->mParent) { 893 return; 894 } 895 if (!req->mParent->CanSend()) { 896 return; 897 } 898 899 ipc::ByteBuf bb; 900 ffi::wgpu_server_pack_work_done(ToFFI(&bb), req->mQueueId); 901 if (!req->mParent->SendServerMessage(std::move(bb))) { 902 NS_ERROR("SendServerMessage failed"); 903 } 904 } 905 906 // TODO: proper destruction 907 908 void WebGPUParent::DeviceCreateSwapChain( 909 RawId aDeviceId, RawId aQueueId, const RGBDescriptor& aDesc, 910 const nsTArray<RawId>& aBufferIds, 911 const layers::RemoteTextureOwnerId& aOwnerId, 912 bool aUseSharedTextureInSwapChain) { 913 switch (aDesc.format()) { 914 case gfx::SurfaceFormat::R8G8B8A8: 915 case gfx::SurfaceFormat::B8G8R8A8: 916 break; 917 default: 918 MOZ_ASSERT_UNREACHABLE("Invalid surface format!"); 919 return; 920 } 921 922 const auto bufferStrideWithMask = 923 Device::BufferStrideWithMask(aDesc.size(), aDesc.format()); 924 if (!bufferStrideWithMask.isValid()) { 925 MOZ_ASSERT_UNREACHABLE("Invalid width / buffer stride!"); 926 return; 927 } 928 929 constexpr uint32_t kBufferAlignmentMask = 0xff; 930 const uint32_t bufferStride = 931 bufferStrideWithMask.value() & ~kBufferAlignmentMask; 932 933 const auto rows = CheckedInt<uint32_t>(aDesc.size().height); 934 if (!rows.isValid()) { 935 MOZ_ASSERT_UNREACHABLE("Invalid height!"); 936 return; 937 } 938 939 if (!mRemoteTextureOwner) { 940 mRemoteTextureOwner = 941 MakeRefPtr<layers::RemoteTextureOwnerClient>(OtherPid()); 942 } 943 mRemoteTextureOwner->RegisterTextureOwner(aOwnerId); 944 945 auto data = MakeRefPtr<PresentationData>(this, aUseSharedTextureInSwapChain, 946 aDeviceId, aQueueId, aDesc, 947 bufferStride, aBufferIds); 948 if (!mPresentationDataMap.emplace(aOwnerId, data).second) { 949 NS_ERROR("External image is already registered as WebGPU canvas!"); 950 } 951 } 952 953 struct ReadbackPresentRequest { 954 ReadbackPresentRequest( 955 const ffi::WGPUGlobal* aContext, RefPtr<PresentationData>& aData, 956 RefPtr<layers::RemoteTextureOwnerClient>& aRemoteTextureOwner, 957 const layers::RemoteTextureId aTextureId, 958 const layers::RemoteTextureOwnerId aOwnerId) 959 : mContext(aContext), 960 mData(aData), 961 mRemoteTextureOwner(aRemoteTextureOwner), 962 mTextureId(aTextureId), 963 mOwnerId(aOwnerId) {} 964 965 const ffi::WGPUGlobal* mContext; 966 RefPtr<PresentationData> mData; 967 RefPtr<layers::RemoteTextureOwnerClient> mRemoteTextureOwner; 968 const layers::RemoteTextureId mTextureId; 969 const layers::RemoteTextureOwnerId mOwnerId; 970 }; 971 972 static void ReadbackPresentCallback(uint8_t* userdata, 973 ffi::WGPUBufferMapAsyncStatus status) { 974 UniquePtr<ReadbackPresentRequest> req( 975 reinterpret_cast<ReadbackPresentRequest*>(userdata)); 976 977 const auto onExit = mozilla::MakeScopeExit([&]() { 978 auto& waitingTextures = req->mData->mWaitingReadbackTexturesForPresent; 979 auto it = waitingTextures.find(req->mTextureId); 980 MOZ_ASSERT(it != waitingTextures.end()); 981 if (it != waitingTextures.end()) { 982 waitingTextures.erase(it); 983 } 984 if (req->mData->mPendingSwapChainDrop.isSome() && waitingTextures.empty()) { 985 if (req->mData->mParent) { 986 auto& pendingDrop = req->mData->mPendingSwapChainDrop.ref(); 987 req->mData->mParent->SwapChainDrop(req->mOwnerId, pendingDrop.mTxnType, 988 pendingDrop.mTxnId); 989 req->mData->mPendingSwapChainDrop = Nothing(); 990 } 991 } 992 }); 993 994 if (!req->mRemoteTextureOwner->IsRegistered(req->mOwnerId)) { 995 // SwapChain is already Destroyed 996 return; 997 } 998 999 RefPtr<PresentationData> data = req->mData; 1000 // get the buffer ID 1001 RawId bufferId; 1002 { 1003 bufferId = data->mQueuedBufferIds.back(); 1004 data->mQueuedBufferIds.pop_back(); 1005 } 1006 1007 // Ensure we'll make the bufferId available for reuse 1008 data->mAvailableBufferIds.push_back(bufferId); 1009 1010 MOZ_LOG(sLogger, LogLevel::Info, 1011 ("ReadbackPresentCallback for buffer %" PRIu64 " status=%d\n", 1012 bufferId, status)); 1013 // copy the data 1014 if (status == ffi::WGPUBufferMapAsyncStatus_Success) { 1015 const auto bufferSize = data->mDesc.size().height * data->mSourcePitch; 1016 ErrorBuffer getRangeError; 1017 const auto mapped = ffi::wgpu_server_buffer_get_mapped_range( 1018 req->mContext, data->mDeviceId, bufferId, 0, bufferSize, 1019 getRangeError.ToFFI()); 1020 getRangeError.CoerceValidationToInternal(); 1021 if (req->mData->mParent) { 1022 req->mData->mParent->ForwardError(getRangeError); 1023 } 1024 if (auto innerError = getRangeError.GetError()) { 1025 MOZ_LOG(sLogger, LogLevel::Info, 1026 ("WebGPU present: buffer get_mapped_range for internal " 1027 "presentation readback failed: %s\n", 1028 innerError->message.get())); 1029 return; 1030 } 1031 1032 MOZ_RELEASE_ASSERT(mapped.length >= bufferSize); 1033 auto textureData = 1034 req->mRemoteTextureOwner->CreateOrRecycleBufferTextureData( 1035 data->mDesc.size(), data->mDesc.format(), req->mOwnerId); 1036 if (!textureData) { 1037 gfxCriticalNoteOnce << "Failed to allocate BufferTextureData"; 1038 return; 1039 } 1040 layers::MappedTextureData mappedData; 1041 if (textureData && textureData->BorrowMappedData(mappedData)) { 1042 uint8_t* src = mapped.ptr; 1043 uint8_t* dst = mappedData.data; 1044 for (auto row = 0; row < data->mDesc.size().height; ++row) { 1045 memcpy(dst, src, mappedData.stride); 1046 dst += mappedData.stride; 1047 src += data->mSourcePitch; 1048 } 1049 req->mRemoteTextureOwner->PushTexture(req->mTextureId, req->mOwnerId, 1050 std::move(textureData)); 1051 } else { 1052 NS_WARNING("WebGPU present skipped: the swapchain is resized!"); 1053 } 1054 ErrorBuffer unmapError; 1055 wgpu_server_buffer_unmap(req->mContext, data->mDeviceId, bufferId, 1056 unmapError.ToFFI()); 1057 unmapError.CoerceValidationToInternal(); 1058 if (req->mData->mParent) { 1059 req->mData->mParent->ForwardError(unmapError); 1060 } 1061 if (auto innerError = unmapError.GetError()) { 1062 MOZ_LOG(sLogger, LogLevel::Info, 1063 ("WebGPU present: buffer unmap for internal presentation " 1064 "readback failed: %s\n", 1065 innerError->message.get())); 1066 } 1067 } else { 1068 // TODO: better handle errors 1069 NS_WARNING("WebGPU frame mapping failed!"); 1070 } 1071 } 1072 1073 struct ReadbackSnapshotRequest { 1074 ReadbackSnapshotRequest(const ffi::WGPUGlobal* aContext, 1075 RefPtr<PresentationData>& aData, 1076 ffi::WGPUBufferId aBufferId, 1077 const ipc::Shmem& aDestShmem) 1078 : mContext(aContext), 1079 mData(aData), 1080 mBufferId(aBufferId), 1081 mDestShmem(aDestShmem) {} 1082 1083 const ffi::WGPUGlobal* mContext; 1084 RefPtr<PresentationData> mData; 1085 const ffi::WGPUBufferId mBufferId; 1086 const ipc::Shmem& mDestShmem; 1087 }; 1088 1089 static void ReadbackSnapshotCallback(uint8_t* userdata, 1090 ffi::WGPUBufferMapAsyncStatus status) { 1091 UniquePtr<ReadbackSnapshotRequest> req( 1092 reinterpret_cast<ReadbackSnapshotRequest*>(userdata)); 1093 1094 RefPtr<PresentationData> data = req->mData; 1095 data->mReadbackSnapshotCallbackCalled = true; 1096 1097 // Ensure we'll make the bufferId available for reuse 1098 data->mAvailableBufferIds.push_back(req->mBufferId); 1099 1100 MOZ_LOG(sLogger, LogLevel::Info, 1101 ("ReadbackSnapshotCallback for buffer %" PRIu64 " status=%d\n", 1102 req->mBufferId, status)); 1103 if (status != ffi::WGPUBufferMapAsyncStatus_Success) { 1104 return; 1105 } 1106 // copy the data 1107 const auto bufferSize = data->mDesc.size().height * data->mSourcePitch; 1108 ErrorBuffer getRangeError; 1109 const auto mapped = ffi::wgpu_server_buffer_get_mapped_range( 1110 req->mContext, data->mDeviceId, req->mBufferId, 0, bufferSize, 1111 getRangeError.ToFFI()); 1112 getRangeError.CoerceValidationToInternal(); 1113 if (req->mData->mParent) { 1114 req->mData->mParent->ForwardError(getRangeError); 1115 } 1116 if (auto innerError = getRangeError.GetError()) { 1117 MOZ_LOG(sLogger, LogLevel::Info, 1118 ("WebGPU present: buffer get_mapped_range for internal " 1119 "presentation readback failed: %s\n", 1120 innerError->message.get())); 1121 return; 1122 } 1123 1124 MOZ_RELEASE_ASSERT(mapped.length >= bufferSize); 1125 1126 uint8_t* src = mapped.ptr; 1127 uint8_t* dst = req->mDestShmem.get<uint8_t>(); 1128 const uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride( 1129 gfx::SurfaceFormat::B8G8R8A8, data->mDesc.size().width); 1130 1131 for (auto row = 0; row < data->mDesc.size().height; ++row) { 1132 memcpy(dst, src, stride); 1133 src += data->mSourcePitch; 1134 dst += stride; 1135 } 1136 1137 ErrorBuffer unmapError; 1138 wgpu_server_buffer_unmap(req->mContext, data->mDeviceId, req->mBufferId, 1139 unmapError.ToFFI()); 1140 unmapError.CoerceValidationToInternal(); 1141 if (req->mData->mParent) { 1142 req->mData->mParent->ForwardError(unmapError); 1143 } 1144 if (auto innerError = unmapError.GetError()) { 1145 MOZ_LOG(sLogger, LogLevel::Info, 1146 ("WebGPU snapshot: buffer unmap for internal presentation " 1147 "readback failed: %s\n", 1148 innerError->message.get())); 1149 } 1150 } 1151 1152 ipc::IPCResult WebGPUParent::GetFrontBufferSnapshot( 1153 IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId, 1154 const RawId& aCommandEncoderId, const RawId& aCommandBufferId, 1155 Maybe<Shmem>& aShmem, gfx::IntSize& aSize, uint32_t& aByteStride) { 1156 const auto& lookup = mPresentationDataMap.find(aOwnerId); 1157 if (lookup == mPresentationDataMap.end()) { 1158 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1159 return IPC_OK(); 1160 } 1161 1162 RefPtr<PresentationData> data = lookup->second.get(); 1163 data->mReadbackSnapshotCallbackCalled = false; 1164 aSize = data->mDesc.size(); 1165 uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride( 1166 data->mDesc.format(), aSize.width); 1167 aByteStride = stride; 1168 uint32_t len = data->mDesc.size().height * stride; 1169 Shmem shmem; 1170 if (!AllocShmem(len, &shmem)) { 1171 return IPC_OK(); 1172 } 1173 1174 if (data->mLastSubmittedTextureId.isNothing()) { 1175 return IPC_OK(); 1176 } 1177 1178 auto it = mSharedTextures.find(data->mLastSubmittedTextureId.ref()); 1179 // Shared texture is already invalid and posted to RemoteTextureMap 1180 if (it == mSharedTextures.end()) { 1181 if (!mRemoteTextureOwner || !mRemoteTextureOwner->IsRegistered(aOwnerId)) { 1182 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1183 return IPC_OK(); 1184 } 1185 if (!data->mUseSharedTextureInSwapChain) { 1186 ffi::wgpu_server_device_poll(mContext.get(), data->mDeviceId, true); 1187 } 1188 mRemoteTextureOwner->GetLatestBufferSnapshot(aOwnerId, shmem, aSize); 1189 aShmem.emplace(std::move(shmem)); 1190 return IPC_OK(); 1191 } 1192 1193 // Readback synchronously 1194 1195 RawId bufferId = 0; 1196 const auto& size = data->mDesc.size(); 1197 const auto bufferSize = data->mDesc.size().height * data->mSourcePitch; 1198 1199 // step 1: find an available staging buffer, or create one 1200 { 1201 if (!data->mAvailableBufferIds.empty()) { 1202 bufferId = data->mAvailableBufferIds.back(); 1203 data->mAvailableBufferIds.pop_back(); 1204 } else if (!data->mUnassignedBufferIds.empty()) { 1205 bufferId = data->mUnassignedBufferIds.back(); 1206 data->mUnassignedBufferIds.pop_back(); 1207 1208 ffi::WGPUBufferUsages usage = 1209 WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ; 1210 1211 ErrorBuffer error; 1212 ffi::wgpu_server_device_create_buffer(mContext.get(), data->mDeviceId, 1213 bufferId, nullptr, bufferSize, 1214 usage, false, error.ToFFI()); 1215 if (ForwardError(error)) { 1216 return IPC_OK(); 1217 } 1218 } else { 1219 bufferId = 0; 1220 } 1221 } 1222 1223 MOZ_LOG(sLogger, LogLevel::Info, 1224 ("GetFrontBufferSnapshot with buffer %" PRIu64 "\n", bufferId)); 1225 if (!bufferId) { 1226 // TODO: add a warning - no buffer are available! 1227 return IPC_OK(); 1228 } 1229 1230 // step 3: submit a copy command for the frame 1231 ffi::WGPUCommandEncoderDescriptor encoderDesc = {}; 1232 { 1233 ErrorBuffer error; 1234 ffi::wgpu_server_device_create_encoder(mContext.get(), data->mDeviceId, 1235 &encoderDesc, aCommandEncoderId, 1236 error.ToFFI()); 1237 if (ForwardError(error)) { 1238 return IPC_OK(); 1239 } 1240 } 1241 1242 if (data->mLastSubmittedTextureId.isNothing()) { 1243 return IPC_OK(); 1244 } 1245 1246 const ffi::WGPUTexelCopyTextureInfo texView = { 1247 data->mLastSubmittedTextureId.ref(), 1248 }; 1249 const ffi::WGPUTexelCopyBufferLayout bufLayout = { 1250 0, 1251 &data->mSourcePitch, 1252 nullptr, 1253 }; 1254 const ffi::WGPUExtent3d extent = { 1255 static_cast<uint32_t>(size.width), 1256 static_cast<uint32_t>(size.height), 1257 1, 1258 }; 1259 1260 { 1261 ErrorBuffer error; 1262 ffi::wgpu_server_encoder_copy_texture_to_buffer( 1263 mContext.get(), data->mDeviceId, aCommandEncoderId, &texView, bufferId, 1264 &bufLayout, &extent, error.ToFFI()); 1265 if (ForwardError(error)) { 1266 return IPC_OK(); 1267 } 1268 } 1269 ffi::WGPUCommandBufferDescriptor commandDesc = {}; 1270 { 1271 ErrorBuffer error; 1272 ffi::wgpu_server_encoder_finish(mContext.get(), data->mDeviceId, 1273 aCommandEncoderId, aCommandBufferId, 1274 &commandDesc, error.ToFFI()); 1275 if (ForwardError(error)) { 1276 ffi::wgpu_server_command_encoder_drop(mContext.get(), aCommandEncoderId); 1277 ffi::wgpu_server_command_buffer_drop(mContext.get(), aCommandBufferId); 1278 return IPC_OK(); 1279 } 1280 } 1281 1282 { 1283 ErrorBuffer error; 1284 ffi::wgpu_server_queue_submit(mContext.get(), data->mDeviceId, 1285 data->mQueueId, {&aCommandBufferId, 1}, 1286 error.ToFFI()); 1287 ffi::wgpu_server_command_encoder_drop(mContext.get(), aCommandEncoderId); 1288 ffi::wgpu_server_command_buffer_drop(mContext.get(), aCommandBufferId); 1289 if (ForwardError(error)) { 1290 return IPC_OK(); 1291 } 1292 } 1293 1294 auto snapshotRequest = MakeUnique<ReadbackSnapshotRequest>( 1295 mContext.get(), data, bufferId, shmem); 1296 1297 ffi::WGPUBufferMapClosure closure = { 1298 &ReadbackSnapshotCallback, 1299 reinterpret_cast<uint8_t*>(snapshotRequest.release())}; 1300 1301 ErrorBuffer error; 1302 ffi::wgpu_server_buffer_map(mContext.get(), data->mDeviceId, bufferId, 0, 1303 bufferSize, ffi::WGPUHostMap_Read, closure, 1304 error.ToFFI()); 1305 if (ForwardError(error)) { 1306 return IPC_OK(); 1307 } 1308 1309 // Callback should be called during the poll. 1310 ffi::wgpu_server_poll_all_devices(mContext.get(), true); 1311 1312 // Check if ReadbackSnapshotCallback is called. 1313 MOZ_RELEASE_ASSERT(data->mReadbackSnapshotCallbackCalled == true); 1314 1315 aShmem.emplace(std::move(shmem)); 1316 return IPC_OK(); 1317 } 1318 1319 void WebGPUParent::PostSharedTexture( 1320 const std::shared_ptr<SharedTexture>&& aSharedTexture, 1321 const layers::RemoteTextureId aRemoteTextureId, 1322 const layers::RemoteTextureOwnerId aOwnerId) { 1323 const auto& lookup = mPresentationDataMap.find(aOwnerId); 1324 if (lookup == mPresentationDataMap.end() || !mRemoteTextureOwner || 1325 !mRemoteTextureOwner->IsRegistered(aOwnerId)) { 1326 NS_WARNING("WebGPU presenting on a destroyed swap chain!"); 1327 return; 1328 } 1329 1330 const auto surfaceFormat = gfx::SurfaceFormat::B8G8R8A8; 1331 const auto size = aSharedTexture->GetSize(); 1332 1333 RefPtr<PresentationData> data = lookup->second.get(); 1334 1335 Maybe<layers::SurfaceDescriptor> desc = aSharedTexture->ToSurfaceDescriptor(); 1336 if (!desc) { 1337 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1338 return; 1339 } 1340 1341 mRemoteTextureOwner->PushTexture(aRemoteTextureId, aOwnerId, aSharedTexture, 1342 size, surfaceFormat, *desc); 1343 1344 auto recycledTexture = mRemoteTextureOwner->GetRecycledSharedTexture( 1345 size, surfaceFormat, desc->type(), aOwnerId); 1346 if (recycledTexture) { 1347 recycledTexture->CleanForRecycling(); 1348 data->mRecycledSharedTextures.push_back(recycledTexture); 1349 } 1350 } 1351 1352 RefPtr<gfx::FileHandleWrapper> WebGPUParent::GetDeviceFenceHandle( 1353 const RawId aDeviceId) { 1354 auto it = mDeviceFenceHandles.find(aDeviceId); 1355 if (it == mDeviceFenceHandles.end()) { 1356 return nullptr; 1357 } 1358 return it->second; 1359 } 1360 1361 void WebGPUParent::SwapChainPresent( 1362 RawId aTextureId, RawId aCommandEncoderId, RawId aCommandBufferId, 1363 const layers::RemoteTextureId& aRemoteTextureId, 1364 const layers::RemoteTextureOwnerId& aOwnerId) { 1365 // step 0: get the data associated with the swapchain 1366 const auto& lookup = mPresentationDataMap.find(aOwnerId); 1367 if (lookup == mPresentationDataMap.end() || !mRemoteTextureOwner || 1368 !mRemoteTextureOwner->IsRegistered(aOwnerId)) { 1369 NS_WARNING("WebGPU presenting on a destroyed swap chain!"); 1370 return; 1371 } 1372 1373 RefPtr<PresentationData> data = lookup->second.get(); 1374 1375 if (data->mUseSharedTextureInSwapChain) { 1376 auto it = mSharedTextures.find(aTextureId); 1377 if (it == mSharedTextures.end()) { 1378 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1379 return; 1380 } 1381 std::shared_ptr<SharedTexture> sharedTexture = it->second; 1382 mSharedTextures.erase(it); 1383 1384 MOZ_ASSERT(sharedTexture->GetOwnerId() == aOwnerId); 1385 1386 PostSharedTexture(std::move(sharedTexture), aRemoteTextureId, aOwnerId); 1387 return; 1388 } 1389 1390 RawId bufferId = 0; 1391 const auto& size = data->mDesc.size(); 1392 const auto bufferSize = data->mDesc.size().height * data->mSourcePitch; 1393 1394 // step 1: find an available staging buffer, or create one 1395 { 1396 if (!data->mAvailableBufferIds.empty()) { 1397 bufferId = data->mAvailableBufferIds.back(); 1398 data->mAvailableBufferIds.pop_back(); 1399 } else if (!data->mUnassignedBufferIds.empty()) { 1400 bufferId = data->mUnassignedBufferIds.back(); 1401 data->mUnassignedBufferIds.pop_back(); 1402 1403 ffi::WGPUBufferUsages usage = 1404 WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ; 1405 1406 ErrorBuffer error; 1407 ffi::wgpu_server_device_create_buffer(mContext.get(), data->mDeviceId, 1408 bufferId, nullptr, bufferSize, 1409 usage, false, error.ToFFI()); 1410 if (ForwardError(error)) { 1411 return; 1412 } 1413 } else { 1414 bufferId = 0; 1415 } 1416 1417 if (bufferId) { 1418 data->mQueuedBufferIds.insert(data->mQueuedBufferIds.begin(), bufferId); 1419 } 1420 } 1421 1422 MOZ_LOG(sLogger, LogLevel::Info, 1423 ("RecvSwapChainPresent with buffer %" PRIu64 "\n", bufferId)); 1424 if (!bufferId) { 1425 // TODO: add a warning - no buffer are available! 1426 return; 1427 } 1428 1429 // step 3: submit a copy command for the frame 1430 ffi::WGPUCommandEncoderDescriptor encoderDesc = {}; 1431 { 1432 ErrorBuffer error; 1433 ffi::wgpu_server_device_create_encoder(mContext.get(), data->mDeviceId, 1434 &encoderDesc, aCommandEncoderId, 1435 error.ToFFI()); 1436 if (ForwardError(error)) { 1437 return; 1438 } 1439 } 1440 1441 const ffi::WGPUTexelCopyTextureInfo texView = { 1442 aTextureId, 1443 }; 1444 const ffi::WGPUTexelCopyBufferLayout bufLayout = { 1445 0, 1446 &data->mSourcePitch, 1447 nullptr, 1448 }; 1449 const ffi::WGPUExtent3d extent = { 1450 static_cast<uint32_t>(size.width), 1451 static_cast<uint32_t>(size.height), 1452 1, 1453 }; 1454 1455 { 1456 ErrorBuffer error; 1457 ffi::wgpu_server_encoder_copy_texture_to_buffer( 1458 mContext.get(), data->mDeviceId, aCommandEncoderId, &texView, bufferId, 1459 &bufLayout, &extent, error.ToFFI()); 1460 if (ForwardError(error)) { 1461 return; 1462 } 1463 } 1464 ffi::WGPUCommandBufferDescriptor commandDesc = {}; 1465 { 1466 ErrorBuffer error; 1467 ffi::wgpu_server_encoder_finish(mContext.get(), data->mDeviceId, 1468 aCommandEncoderId, aCommandBufferId, 1469 &commandDesc, error.ToFFI()); 1470 if (ForwardError(error)) { 1471 ffi::wgpu_server_command_encoder_drop(mContext.get(), aCommandEncoderId); 1472 ffi::wgpu_server_command_buffer_drop(mContext.get(), aCommandBufferId); 1473 return; 1474 } 1475 } 1476 1477 { 1478 ErrorBuffer error; 1479 ffi::wgpu_server_queue_submit(mContext.get(), data->mDeviceId, 1480 data->mQueueId, {&aCommandBufferId, 1}, 1481 error.ToFFI()); 1482 ffi::wgpu_server_command_encoder_drop(mContext.get(), aCommandEncoderId); 1483 ffi::wgpu_server_command_buffer_drop(mContext.get(), aCommandBufferId); 1484 if (ForwardError(error)) { 1485 return; 1486 } 1487 } 1488 1489 auto& waitingTextures = data->mWaitingReadbackTexturesForPresent; 1490 auto it = waitingTextures.find(aRemoteTextureId); 1491 MOZ_ASSERT(it == waitingTextures.end()); 1492 if (it == waitingTextures.end()) { 1493 waitingTextures.emplace(aRemoteTextureId); 1494 } 1495 1496 // step 4: request the pixels to be copied into the shared texture 1497 // TODO: this isn't strictly necessary. When WR wants to Lock() the external 1498 // texture, 1499 // we can just give it the contents of the last mapped buffer instead of the 1500 // copy. 1501 auto presentRequest = MakeUnique<ReadbackPresentRequest>( 1502 mContext.get(), data, mRemoteTextureOwner, aRemoteTextureId, aOwnerId); 1503 1504 ffi::WGPUBufferMapClosure closure = { 1505 &ReadbackPresentCallback, 1506 reinterpret_cast<uint8_t*>(presentRequest.release())}; 1507 1508 ErrorBuffer error; 1509 ffi::wgpu_server_buffer_map(mContext.get(), data->mDeviceId, bufferId, 0, 1510 bufferSize, ffi::WGPUHostMap_Read, closure, 1511 error.ToFFI()); 1512 if (ForwardError(error)) { 1513 return; 1514 } 1515 } 1516 1517 void WebGPUParent::SwapChainDrop(const layers::RemoteTextureOwnerId& aOwnerId, 1518 layers::RemoteTextureTxnType aTxnType, 1519 layers::RemoteTextureTxnId aTxnId) { 1520 const auto& lookup = mPresentationDataMap.find(aOwnerId); 1521 MOZ_ASSERT(lookup != mPresentationDataMap.end()); 1522 if (lookup == mPresentationDataMap.end()) { 1523 NS_WARNING("WebGPU presenting on a destroyed swap chain!"); 1524 return; 1525 } 1526 1527 RefPtr<PresentationData> data = lookup->second.get(); 1528 1529 auto waitingCount = data->mWaitingReadbackTexturesForPresent.size(); 1530 if (waitingCount > 0) { 1531 // Defer SwapChainDrop until readback complete 1532 data->mPendingSwapChainDrop = Some(PendingSwapChainDrop{aTxnType, aTxnId}); 1533 return; 1534 } 1535 1536 if (mRemoteTextureOwner) { 1537 if (aTxnType && aTxnId) { 1538 mRemoteTextureOwner->WaitForTxn(aOwnerId, aTxnType, aTxnId); 1539 } 1540 mRemoteTextureOwner->UnregisterTextureOwner(aOwnerId); 1541 } 1542 1543 mPresentationDataMap.erase(lookup); 1544 1545 for (const auto bid : data->mAvailableBufferIds) { 1546 ffi::wgpu_server_buffer_drop(mContext.get(), bid); 1547 data->mUnassignedBufferIds.push_back(bid); 1548 } 1549 for (const auto bid : data->mQueuedBufferIds) { 1550 ffi::wgpu_server_buffer_drop(mContext.get(), bid); 1551 data->mUnassignedBufferIds.push_back(bid); 1552 } 1553 1554 ipc::ByteBuf bb; 1555 ffi::wgpu_server_pack_free_swap_chain_buffer_ids( 1556 ToFFI(&bb), 1557 {data->mUnassignedBufferIds.data(), data->mUnassignedBufferIds.size()}); 1558 if (!SendServerMessage(std::move(bb))) { 1559 NS_ERROR("SendServerMessage failed"); 1560 } 1561 } 1562 1563 void WebGPUParent::ActorDestroy(ActorDestroyReason aWhy) { 1564 mTimer.Stop(); 1565 mPresentationDataMap.clear(); 1566 if (mRemoteTextureOwner) { 1567 mRemoteTextureOwner->UnregisterAllTextureOwners(); 1568 mRemoteTextureOwner = nullptr; 1569 } 1570 mActiveDeviceIds.Clear(); 1571 mContext = nullptr; 1572 } 1573 1574 ipc::IPCResult WebGPUParent::RecvMessages( 1575 uint32_t nrOfMessages, ipc::ByteBuf&& aSerializedMessages, 1576 nsTArray<ipc::ByteBuf>&& aDataBuffers, 1577 nsTArray<MutableSharedMemoryHandle>&& aShmems) { 1578 MOZ_ASSERT(mTempMappings.empty()); 1579 1580 mTempMappings.reserve(aShmems.Length()); 1581 1582 nsTArray<ffi::WGPUFfiSlice_u8> shmem_mappings(aShmems.Length()); 1583 1584 for (const auto& shmem : aShmems) { 1585 auto mapping = shmem.Map(); 1586 1587 auto* ptr = mapping.DataAs<uint8_t>(); 1588 auto len = mapping.Size(); 1589 ffi::WGPUFfiSlice_u8 byte_slice{ptr, len}; 1590 shmem_mappings.AppendElement(std::move(byte_slice)); 1591 1592 // `aShmem` may be an invalid handle, however this will simply result in an 1593 // invalid mapping with 0 size, which we use safely. 1594 mTempMappings.push_back( 1595 std::make_shared<ipc::SharedMemoryMapping>(std::move(mapping))); 1596 } 1597 1598 ffi::WGPUFfiSlice_ByteBuf data_buffers{ToFFI(aDataBuffers.Elements()), 1599 aDataBuffers.Length()}; 1600 1601 ffi::WGPUFfiSlice_FfiSlice_u8 shmem_mapping_slices{shmem_mappings.Elements(), 1602 shmem_mappings.Length()}; 1603 1604 ffi::wgpu_server_messages(mContext.get(), nrOfMessages, 1605 ToFFI(&aSerializedMessages), data_buffers, 1606 shmem_mapping_slices); 1607 1608 mTempMappings.clear(); 1609 1610 return IPC_OK(); 1611 } 1612 1613 ipc::IPCResult WebGPUParent::RecvCreateExternalTextureSource( 1614 RawId aDeviceId, RawId aQueueId, RawId aExternalTextureSourceId, 1615 const ExternalTextureSourceDescriptor& aDesc) { 1616 MOZ_RELEASE_ASSERT(mExternalTextureSources.find(aExternalTextureSourceId) == 1617 mExternalTextureSources.end()); 1618 mExternalTextureSources.emplace( 1619 aExternalTextureSourceId, 1620 ExternalTextureSourceHost::Create(this, aDeviceId, aQueueId, aDesc)); 1621 1622 return IPC_OK(); 1623 } 1624 1625 void WebGPUParent::DevicePushErrorScope(RawId aDeviceId, 1626 const dom::GPUErrorFilter aFilter) { 1627 const auto& itr = mErrorScopeStackByDevice.find(aDeviceId); 1628 if (itr == mErrorScopeStackByDevice.end()) { 1629 // Content can cause this simply by destroying a device and then 1630 // calling `pushErrorScope`. 1631 return; 1632 } 1633 auto& stack = itr->second; 1634 1635 // Let's prevent `while (true) { pushErrorScope(); }`. 1636 constexpr size_t MAX_ERROR_SCOPE_STACK_SIZE = 1'000'000; 1637 if (stack.size() >= MAX_ERROR_SCOPE_STACK_SIZE) { 1638 nsPrintfCString m("pushErrorScope: Hit MAX_ERROR_SCOPE_STACK_SIZE of %zu", 1639 MAX_ERROR_SCOPE_STACK_SIZE); 1640 ReportError(aDeviceId, dom::GPUErrorFilter::Out_of_memory, m); 1641 return; 1642 } 1643 1644 const auto newScope = ErrorScope{aFilter}; 1645 stack.push_back(newScope); 1646 } 1647 1648 PopErrorScopeResult WebGPUParent::DevicePopErrorScope(RawId aDeviceId) { 1649 const auto popResult = [&]() { 1650 const auto& itr = mErrorScopeStackByDevice.find(aDeviceId); 1651 if (itr == mErrorScopeStackByDevice.end()) { 1652 // Content can cause this simply by destroying a device and then 1653 // calling `popErrorScope`. 1654 return PopErrorScopeResult{PopErrorScopeResultType::DeviceLost}; 1655 } 1656 1657 auto& stack = itr->second; 1658 if (!stack.size()) { 1659 // Content can cause this simply by calling `popErrorScope` when 1660 // there is no error scope pushed. 1661 return PopErrorScopeResult{PopErrorScopeResultType::ThrowOperationError, 1662 "popErrorScope on empty stack"_ns}; 1663 } 1664 1665 const auto& scope = stack.back(); 1666 const auto popLater = MakeScopeExit([&]() { stack.pop_back(); }); 1667 1668 auto ret = PopErrorScopeResult{PopErrorScopeResultType::NoError}; 1669 if (scope.firstMessage) { 1670 ret.message = *scope.firstMessage; 1671 switch (scope.filter) { 1672 case dom::GPUErrorFilter::Validation: 1673 ret.resultType = PopErrorScopeResultType::ValidationError; 1674 break; 1675 case dom::GPUErrorFilter::Out_of_memory: 1676 ret.resultType = PopErrorScopeResultType::OutOfMemory; 1677 break; 1678 case dom::GPUErrorFilter::Internal: 1679 ret.resultType = PopErrorScopeResultType::InternalError; 1680 break; 1681 } 1682 } 1683 return ret; 1684 }(); 1685 return popResult; 1686 } 1687 1688 bool WebGPUParent::UseSharedTextureForSwapChain( 1689 ffi::WGPUSwapChainId aSwapChainId) { 1690 auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0}; 1691 const auto& lookup = mPresentationDataMap.find(ownerId); 1692 if (lookup == mPresentationDataMap.end()) { 1693 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1694 return false; 1695 } 1696 1697 RefPtr<PresentationData> data = lookup->second.get(); 1698 1699 return data->mUseSharedTextureInSwapChain; 1700 } 1701 1702 void WebGPUParent::DisableSharedTextureForSwapChain( 1703 ffi::WGPUSwapChainId aSwapChainId) { 1704 auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0}; 1705 const auto& lookup = mPresentationDataMap.find(ownerId); 1706 if (lookup == mPresentationDataMap.end()) { 1707 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1708 return; 1709 } 1710 1711 RefPtr<PresentationData> data = lookup->second.get(); 1712 1713 if (data->mUseSharedTextureInSwapChain) { 1714 gfxCriticalNote << "Disable SharedTexture for SwapChain: " 1715 << aSwapChainId._0; 1716 } 1717 1718 data->mUseSharedTextureInSwapChain = false; 1719 } 1720 1721 bool WebGPUParent::EnsureSharedTextureForSwapChain( 1722 ffi::WGPUSwapChainId aSwapChainId, ffi::WGPUDeviceId aDeviceId, 1723 ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight, 1724 struct ffi::WGPUTextureFormat aFormat, ffi::WGPUTextureUsages aUsage) { 1725 auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0}; 1726 const auto& lookup = mPresentationDataMap.find(ownerId); 1727 if (lookup == mPresentationDataMap.end()) { 1728 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1729 return false; 1730 } 1731 1732 RefPtr<PresentationData> data = lookup->second.get(); 1733 if (!data->mUseSharedTextureInSwapChain) { 1734 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1735 return false; 1736 } 1737 1738 // Recycled SharedTexture if it exists. 1739 if (!data->mRecycledSharedTextures.empty()) { 1740 std::shared_ptr<SharedTexture> texture = 1741 data->mRecycledSharedTextures.front(); 1742 // Check if the texture is recyclable. 1743 if (texture->mWidth == aWidth && texture->mHeight == aHeight && 1744 texture->mFormat.tag == aFormat.tag && texture->mUsage == aUsage) { 1745 texture->SetOwnerId(ownerId); 1746 data->mRecycledSharedTextures.pop_front(); 1747 mSharedTextures.emplace(aTextureId, texture); 1748 return true; 1749 } 1750 data->mRecycledSharedTextures.clear(); 1751 } 1752 1753 auto sharedTexture = CreateSharedTexture(ownerId, aDeviceId, aTextureId, 1754 aWidth, aHeight, aFormat, aUsage); 1755 return static_cast<bool>(sharedTexture); 1756 } 1757 1758 void WebGPUParent::EnsureSharedTextureForReadBackPresent( 1759 ffi::WGPUSwapChainId aSwapChainId, ffi::WGPUDeviceId aDeviceId, 1760 ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight, 1761 struct ffi::WGPUTextureFormat aFormat, ffi::WGPUTextureUsages aUsage) { 1762 auto ownerId = layers::RemoteTextureOwnerId{aSwapChainId._0}; 1763 const auto& lookup = mPresentationDataMap.find(ownerId); 1764 if (lookup == mPresentationDataMap.end()) { 1765 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1766 return; 1767 } 1768 1769 RefPtr<PresentationData> data = lookup->second.get(); 1770 if (data->mUseSharedTextureInSwapChain) { 1771 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1772 return; 1773 } 1774 1775 UniquePtr<SharedTexture> texture = 1776 SharedTextureReadBackPresent::Create(aWidth, aHeight, aFormat, aUsage); 1777 if (!texture) { 1778 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1779 return; 1780 } 1781 1782 texture->SetOwnerId(ownerId); 1783 std::shared_ptr<SharedTexture> shared(texture.release()); 1784 mSharedTextures[aTextureId] = shared; 1785 } 1786 1787 std::shared_ptr<SharedTexture> WebGPUParent::CreateSharedTexture( 1788 const layers::RemoteTextureOwnerId& aOwnerId, ffi::WGPUDeviceId aDeviceId, 1789 ffi::WGPUTextureId aTextureId, uint32_t aWidth, uint32_t aHeight, 1790 const struct ffi::WGPUTextureFormat aFormat, 1791 ffi::WGPUTextureUsages aUsage) { 1792 MOZ_RELEASE_ASSERT(mSharedTextures.find(aTextureId) == mSharedTextures.end()); 1793 1794 UniquePtr<SharedTexture> texture = 1795 SharedTexture::Create(this, aDeviceId, aWidth, aHeight, aFormat, aUsage); 1796 if (!texture) { 1797 return nullptr; 1798 } 1799 1800 texture->SetOwnerId(aOwnerId); 1801 std::shared_ptr<SharedTexture> shared(texture.release()); 1802 mSharedTextures.emplace(aTextureId, shared); 1803 1804 return shared; 1805 } 1806 1807 std::shared_ptr<SharedTexture> WebGPUParent::GetSharedTexture( 1808 ffi::WGPUTextureId aId) { 1809 auto it = mSharedTextures.find(aId); 1810 if (it == mSharedTextures.end()) { 1811 return nullptr; 1812 } 1813 return it->second; 1814 } 1815 1816 #if defined(XP_WIN) 1817 /* static */ 1818 Maybe<ffi::WGPUFfiLUID> WebGPUParent::GetCompositorDeviceLuid() { 1819 const RefPtr<ID3D11Device> d3d11Device = 1820 gfx::DeviceManagerDx::Get()->GetCompositorDevice(); 1821 if (!d3d11Device) { 1822 gfxCriticalNoteOnce << "CompositorDevice does not exist"; 1823 return Nothing(); 1824 } 1825 1826 RefPtr<IDXGIDevice> dxgiDevice; 1827 d3d11Device->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice)); 1828 1829 RefPtr<IDXGIAdapter> dxgiAdapter; 1830 dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)); 1831 1832 DXGI_ADAPTER_DESC desc; 1833 if (FAILED(dxgiAdapter->GetDesc(&desc))) { 1834 gfxCriticalNoteOnce << "Failed to get DXGI_ADAPTER_DESC"; 1835 return Nothing(); 1836 } 1837 1838 return Some( 1839 ffi::WGPUFfiLUID{desc.AdapterLuid.LowPart, desc.AdapterLuid.HighPart}); 1840 } 1841 #endif 1842 1843 #if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID) 1844 VkImageHandle::~VkImageHandle() { 1845 if (!mParent) { 1846 return; 1847 } 1848 auto* context = mParent->GetContext(); 1849 if (context && mParent->IsDeviceActive(mDeviceId) && mVkImageHandle) { 1850 wgpu_vkimage_destroy(context, mDeviceId, mVkImageHandle); 1851 } 1852 wgpu_vkimage_delete(mVkImageHandle); 1853 } 1854 1855 VkSemaphoreHandle::~VkSemaphoreHandle() { 1856 if (!mParent) { 1857 return; 1858 } 1859 auto* context = mParent->GetContext(); 1860 if (context && mParent->IsDeviceActive(mDeviceId) && mVkSemaphoreHandle) { 1861 wgpu_vksemaphore_destroy(context, mDeviceId, mVkSemaphoreHandle); 1862 } 1863 wgpu_vksemaphore_delete(mVkSemaphoreHandle); 1864 } 1865 #endif 1866 1867 } // namespace mozilla::webgpu