WebRenderUserData.cpp (15280B)
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 "WebRenderUserData.h" 8 9 #include "mozilla/image/WebRenderImageProvider.h" 10 #include "mozilla/layers/AnimationHelper.h" 11 #include "mozilla/layers/CompositorBridgeChild.h" 12 #include "mozilla/layers/ImageClient.h" 13 #include "mozilla/layers/WebRenderBridgeChild.h" 14 #include "mozilla/layers/RenderRootStateManager.h" 15 #include "mozilla/layers/WebRenderMessages.h" 16 #include "mozilla/layers/IpcResourceUpdateQueue.h" 17 #include "mozilla/layers/SharedSurfacesChild.h" 18 #include "mozilla/webgpu/WebGPUChild.h" 19 #include "nsDisplayListInvalidation.h" 20 #include "nsIFrame.h" 21 #include "WebRenderCanvasRenderer.h" 22 23 using namespace mozilla::image; 24 25 namespace mozilla { 26 namespace layers { 27 28 void WebRenderBackgroundData::AddWebRenderCommands( 29 wr::DisplayListBuilder& aBuilder) { 30 aBuilder.PushRect(mBounds, mBounds, true, true, false, mColor); 31 } 32 33 /* static */ 34 bool WebRenderUserData::SupportsAsyncUpdate(nsIFrame* aFrame) { 35 if (!aFrame) { 36 return false; 37 } 38 RefPtr<WebRenderImageData> data = GetWebRenderUserData<WebRenderImageData>( 39 aFrame, static_cast<uint32_t>(DisplayItemType::TYPE_VIDEO)); 40 if (data) { 41 return data->IsAsync(); 42 } 43 44 return false; 45 } 46 47 /* static */ 48 bool WebRenderUserData::ProcessInvalidateForImage(nsIFrame* aFrame, 49 DisplayItemType aType, 50 ImageProviderId aProviderId) { 51 MOZ_ASSERT(aFrame); 52 53 if (!aFrame->HasProperty(WebRenderUserDataProperty::Key())) { 54 aFrame->SchedulePaint(); 55 return false; 56 } 57 58 auto type = static_cast<uint32_t>(aType); 59 RefPtr<WebRenderFallbackData> fallback = 60 GetWebRenderUserData<WebRenderFallbackData>(aFrame, type); 61 if (fallback) { 62 fallback->SetInvalid(true); 63 aFrame->SchedulePaint(); 64 return true; 65 } 66 67 RefPtr<WebRenderImageProviderData> image = 68 GetWebRenderUserData<WebRenderImageProviderData>(aFrame, type); 69 if (image && image->Invalidate(aProviderId)) { 70 return true; 71 } 72 73 aFrame->SchedulePaint(); 74 return false; 75 } 76 77 WebRenderUserData::WebRenderUserData(RenderRootStateManager* aManager, 78 uint32_t aDisplayItemKey, nsIFrame* aFrame) 79 : mManager(aManager), 80 mFrame(aFrame), 81 mDisplayItemKey(aDisplayItemKey), 82 mTable(aManager->GetWebRenderUserDataTable()), 83 mUsed(false) {} 84 85 WebRenderUserData::WebRenderUserData(RenderRootStateManager* aManager, 86 nsDisplayItem* aItem) 87 : mManager(aManager), 88 mFrame(aItem->Frame()), 89 mDisplayItemKey(aItem->GetPerFrameKey()), 90 mTable(aManager->GetWebRenderUserDataTable()), 91 mUsed(false) {} 92 93 WebRenderUserData::~WebRenderUserData() = default; 94 95 void WebRenderUserData::RemoveFromTable() { mTable->Remove(this); } 96 97 WebRenderBridgeChild* WebRenderUserData::WrBridge() const { 98 return mManager->WrBridge(); 99 } 100 101 WebRenderImageData::WebRenderImageData(RenderRootStateManager* aManager, 102 nsDisplayItem* aItem) 103 : WebRenderUserData(aManager, aItem) {} 104 105 WebRenderImageData::WebRenderImageData(RenderRootStateManager* aManager, 106 uint32_t aDisplayItemKey, 107 nsIFrame* aFrame) 108 : WebRenderUserData(aManager, aDisplayItemKey, aFrame) {} 109 110 WebRenderImageData::~WebRenderImageData() { 111 ClearImageKey(); 112 113 if (mPipelineId) { 114 mManager->RemovePipelineIdForCompositable(mPipelineId.ref()); 115 } 116 } 117 118 void WebRenderImageData::ClearImageKey() { 119 if (mKey) { 120 mManager->AddImageKeyForDiscard(mKey.value()); 121 if (mTextureOfImage) { 122 WrBridge()->ReleaseTextureOfImage(mKey.value()); 123 mTextureOfImage = nullptr; 124 } 125 mKey.reset(); 126 } 127 MOZ_ASSERT(!mTextureOfImage); 128 } 129 130 Maybe<wr::ImageKey> WebRenderImageData::UpdateImageKey( 131 ImageContainer* aContainer, wr::IpcResourceUpdateQueue& aResources, 132 bool aFallback) { 133 MOZ_ASSERT(aContainer); 134 135 if (mContainer != aContainer) { 136 mContainer = aContainer; 137 } 138 139 CreateImageClientIfNeeded(); 140 if (!mImageClient) { 141 return Nothing(); 142 } 143 144 MOZ_ASSERT(mImageClient->AsImageClientSingle()); 145 146 ImageClientSingle* imageClient = mImageClient->AsImageClientSingle(); 147 uint32_t oldCounter = imageClient->GetLastUpdateGenerationCounter(); 148 149 bool ret = imageClient->UpdateImage(aContainer); 150 RefPtr<TextureClient> currentTexture = imageClient->GetForwardedTexture(); 151 if (!ret || !currentTexture) { 152 // Delete old key 153 ClearImageKey(); 154 return Nothing(); 155 } 156 157 // Reuse old key if generation is not updated. 158 if (!aFallback && 159 oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) { 160 return mKey; 161 } 162 163 // If we already had a texture and the format hasn't changed, better to reuse 164 // the image keys than create new ones. 165 bool useUpdate = mKey.isSome() && !!mTextureOfImage && !!currentTexture && 166 mTextureOfImage->GetSize() == currentTexture->GetSize() && 167 mTextureOfImage->GetFormat() == currentTexture->GetFormat(); 168 169 wr::MaybeExternalImageId extId = currentTexture->GetExternalImageKey(); 170 MOZ_RELEASE_ASSERT(extId.isSome()); 171 172 if (useUpdate) { 173 MOZ_ASSERT(mKey.isSome()); 174 MOZ_ASSERT(mTextureOfImage); 175 aResources.PushExternalImageForTexture( 176 extId.ref(), mKey.ref(), currentTexture, /* aIsUpdate */ true); 177 } else { 178 ClearImageKey(); 179 wr::WrImageKey key = WrBridge()->GetNextImageKey(); 180 aResources.PushExternalImageForTexture(extId.ref(), key, currentTexture, 181 /* aIsUpdate */ false); 182 mKey = Some(key); 183 } 184 185 mTextureOfImage = currentTexture; 186 return mKey; 187 } 188 189 already_AddRefed<ImageClient> WebRenderImageData::GetImageClient() { 190 RefPtr<ImageClient> imageClient = mImageClient; 191 return imageClient.forget(); 192 } 193 194 void WebRenderImageData::CreateAsyncImageWebRenderCommands( 195 mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer, 196 const StackingContextHelper& aSc, const LayoutDeviceRect& aBounds, 197 const LayoutDeviceRect& aSCBounds, wr::WrRotation aRotation, 198 const wr::ImageRendering& aFilter, const wr::MixBlendMode& aMixBlendMode, 199 bool aIsBackfaceVisible) { 200 MOZ_ASSERT(aContainer->IsAsync()); 201 202 if (mPipelineId.isSome() && mContainer != aContainer) { 203 // In this case, we need to remove the existed pipeline and create new one 204 // because the ImageContainer is changed. 205 WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref()); 206 mPipelineId.reset(); 207 } 208 209 if (!mPipelineId) { 210 // Alloc async image pipeline id. 211 mPipelineId = 212 Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId()); 213 WrBridge()->AddPipelineIdForCompositable( 214 mPipelineId.ref(), aContainer->GetAsyncContainerHandle(), 215 CompositableHandleOwner::ImageBridge); 216 mContainer = aContainer; 217 } 218 MOZ_ASSERT(!mImageClient); 219 220 // Push IFrame for async image pipeline. 221 // 222 // We don't push a stacking context for this async image pipeline here. 223 // Instead, we do it inside the iframe that hosts the image. As a result, 224 // a bunch of the calculations normally done as part of that stacking 225 // context need to be done manually and pushed over to the parent side, 226 // where it will be done when we build the display list for the iframe. 227 // That happens in AsyncImagePipelineManager. 228 aBuilder.PushIFrame(aBounds, aIsBackfaceVisible, mPipelineId.ref(), 229 /*ignoreMissingPipelines*/ false); 230 231 WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline( 232 mPipelineId.value(), aSCBounds, aRotation, aFilter, aMixBlendMode)); 233 } 234 235 void WebRenderImageData::CreateImageClientIfNeeded() { 236 if (!mImageClient) { 237 mImageClient = ImageClient::CreateImageClient( 238 CompositableType::IMAGE, ImageUsageType::WebRenderImageData, WrBridge(), 239 TextureFlags::DEFAULT); 240 if (!mImageClient) { 241 return; 242 } 243 244 mImageClient->Connect(); 245 } 246 } 247 248 WebRenderImageProviderData::WebRenderImageProviderData( 249 RenderRootStateManager* aManager, nsDisplayItem* aItem) 250 : WebRenderUserData(aManager, aItem) {} 251 252 WebRenderImageProviderData::WebRenderImageProviderData( 253 RenderRootStateManager* aManager, uint32_t aDisplayItemKey, 254 nsIFrame* aFrame) 255 : WebRenderUserData(aManager, aDisplayItemKey, aFrame) {} 256 257 WebRenderImageProviderData::~WebRenderImageProviderData() = default; 258 259 Maybe<wr::ImageKey> WebRenderImageProviderData::UpdateImageKey( 260 WebRenderImageProvider* aProvider, ImgDrawResult aDrawResult, 261 wr::IpcResourceUpdateQueue& aResources) { 262 if (mProvider != aProvider) { 263 mProvider = aProvider; 264 } 265 266 wr::ImageKey key = {}; 267 nsresult rv = mProvider ? mProvider->UpdateKey(mManager, aResources, key) 268 : NS_ERROR_FAILURE; 269 mKey = NS_SUCCEEDED(rv) ? Some(key) : Nothing(); 270 mDrawResult = aDrawResult; 271 return mKey; 272 } 273 274 bool WebRenderImageProviderData::Invalidate(ImageProviderId aProviderId) const { 275 if (!aProviderId || !mProvider || mProvider->GetProviderId() != aProviderId || 276 !mKey) { 277 return false; 278 } 279 280 if (mDrawResult != ImgDrawResult::SUCCESS && 281 mDrawResult != ImgDrawResult::BAD_IMAGE) { 282 return false; 283 } 284 285 wr::ImageKey key = {}; 286 nsresult rv = 287 mProvider->UpdateKey(mManager, mManager->AsyncResourceUpdates(), key); 288 return NS_SUCCEEDED(rv) && mKey.ref() == key; 289 } 290 291 WebRenderFallbackData::WebRenderFallbackData(RenderRootStateManager* aManager, 292 nsDisplayItem* aItem) 293 : WebRenderFallbackData(aManager, aItem->GetPerFrameKey(), aItem->Frame()) { 294 } 295 296 WebRenderFallbackData::WebRenderFallbackData(RenderRootStateManager* aManager, 297 uint32_t aDisplayItemKey, 298 nsIFrame* aFrame) 299 : WebRenderUserData(aManager, aDisplayItemKey, aFrame), 300 mOpacity(1.0f), 301 mInvalid(false) {} 302 303 WebRenderFallbackData::~WebRenderFallbackData() { ClearImageKey(); } 304 305 void WebRenderFallbackData::SetBlobImageKey(const wr::BlobImageKey& aKey) { 306 ClearImageKey(); 307 mBlobKey = Some(aKey); 308 } 309 310 Maybe<wr::ImageKey> WebRenderFallbackData::GetImageKey() { 311 if (mBlobKey) { 312 return Some(wr::AsImageKey(mBlobKey.value())); 313 } 314 315 if (mImageData) { 316 return mImageData->GetImageKey(); 317 } 318 319 return Nothing(); 320 } 321 322 void WebRenderFallbackData::ClearImageKey() { 323 if (mImageData) { 324 mImageData->ClearImageKey(); 325 mImageData = nullptr; 326 } 327 328 if (mBlobKey) { 329 mManager->AddBlobImageKeyForDiscard(mBlobKey.value()); 330 mBlobKey.reset(); 331 } 332 } 333 334 WebRenderImageData* WebRenderFallbackData::PaintIntoImage() { 335 if (mBlobKey) { 336 mManager->AddBlobImageKeyForDiscard(mBlobKey.value()); 337 mBlobKey.reset(); 338 } 339 340 if (mImageData) { 341 return mImageData.get(); 342 } 343 344 mImageData = MakeAndAddRef<WebRenderImageData>(mManager.get(), 345 mDisplayItemKey, mFrame); 346 347 return mImageData.get(); 348 } 349 350 WebRenderAPZAnimationData::WebRenderAPZAnimationData( 351 RenderRootStateManager* aManager, nsDisplayItem* aItem) 352 : WebRenderAPZAnimationData(aManager, aItem->GetPerFrameKey(), 353 aItem->Frame()) {} 354 355 WebRenderAPZAnimationData::WebRenderAPZAnimationData( 356 RenderRootStateManager* aManager, uint32_t aDisplayItemKey, 357 nsIFrame* aFrame) 358 : WebRenderUserData(aManager, aDisplayItemKey, aFrame), 359 mAnimationId(AnimationHelper::GetNextCompositorAnimationsId()) {} 360 361 WebRenderAnimationData::WebRenderAnimationData(RenderRootStateManager* aManager, 362 nsDisplayItem* aItem) 363 : WebRenderUserData(aManager, aItem) {} 364 365 WebRenderAnimationData::WebRenderAnimationData(RenderRootStateManager* aManager, 366 uint32_t aDisplayItemKey, 367 nsIFrame* aFrame) 368 : WebRenderUserData(aManager, aDisplayItemKey, aFrame) {} 369 370 WebRenderAnimationData::~WebRenderAnimationData() { 371 // It may be the case that nsDisplayItem that created this WebRenderUserData 372 // gets destroyed without getting a chance to discard the compositor animation 373 // id, so we should do it as part of cleanup here. 374 uint64_t animationId = mAnimationInfo.GetCompositorAnimationsId(); 375 // animationId might be 0 if mAnimationInfo never held any active animations. 376 if (animationId) { 377 mManager->AddCompositorAnimationsIdForDiscard(animationId); 378 } 379 } 380 381 WebRenderCanvasData::WebRenderCanvasData(RenderRootStateManager* aManager, 382 nsDisplayItem* aItem) 383 : WebRenderUserData(aManager, aItem) {} 384 385 WebRenderCanvasData::WebRenderCanvasData(RenderRootStateManager* aManager, 386 uint32_t aDisplayItemKey, 387 nsIFrame* aFrame) 388 : WebRenderUserData(aManager, aDisplayItemKey, aFrame) {} 389 390 WebRenderCanvasData::~WebRenderCanvasData() { 391 if (mCanvasRenderer) { 392 mCanvasRenderer->ClearCachedResources(); 393 } 394 } 395 396 void WebRenderCanvasData::ClearCanvasRenderer() { mCanvasRenderer = nullptr; } 397 398 WebRenderCanvasRendererAsync* WebRenderCanvasData::GetCanvasRenderer() { 399 return mCanvasRenderer.get(); 400 } 401 402 WebRenderCanvasRendererAsync* WebRenderCanvasData::CreateCanvasRenderer() { 403 mCanvasRenderer = new WebRenderCanvasRendererAsync(mManager); 404 return mCanvasRenderer.get(); 405 } 406 407 bool WebRenderCanvasData::SetCanvasRenderer(CanvasRenderer* aCanvasRenderer) { 408 if (!aCanvasRenderer || !aCanvasRenderer->AsWebRenderCanvasRendererAsync()) { 409 return false; 410 } 411 412 auto* renderer = aCanvasRenderer->AsWebRenderCanvasRendererAsync(); 413 if (mManager != renderer->GetRenderRootStateManager()) { 414 return false; 415 } 416 417 mCanvasRenderer = renderer; 418 return true; 419 } 420 421 void WebRenderCanvasData::SetImageContainer(ImageContainer* aImageContainer) { 422 mContainer = aImageContainer; 423 } 424 425 ImageContainer* WebRenderCanvasData::GetImageContainer() { 426 if (!mContainer) { 427 mContainer = MakeAndAddRef<ImageContainer>(ImageUsageType::Canvas, 428 ImageContainer::SYNCHRONOUS); 429 } 430 return mContainer; 431 } 432 433 void WebRenderCanvasData::ClearImageContainer() { mContainer = nullptr; } 434 435 void DestroyWebRenderUserDataTable(WebRenderUserDataTable* aTable) { 436 for (const auto& value : aTable->Values()) { 437 value->RemoveFromTable(); 438 } 439 delete aTable; 440 } 441 442 WebRenderMaskData::WebRenderMaskData(RenderRootStateManager* aManager, 443 nsDisplayItem* aItem) 444 : WebRenderMaskData(aManager, aItem->GetPerFrameKey(), aItem->Frame()) {} 445 WebRenderMaskData::WebRenderMaskData(RenderRootStateManager* aManager, 446 uint32_t aDisplayItemKey, nsIFrame* aFrame) 447 : WebRenderUserData(aManager, aDisplayItemKey, aFrame), 448 mMaskStyle(nsStyleImageLayers::LayerType::Mask), 449 mShouldHandleOpacity(false) { 450 MOZ_COUNT_CTOR(WebRenderMaskData); 451 } 452 453 } // namespace layers 454 } // namespace mozilla