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/. */
7 #include "WebRenderUserData.h"
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"
21 #include "WebRenderCanvasRenderer.h"
23 using namespace mozilla::image
;
28 void WebRenderBackgroundData::AddWebRenderCommands(
29 wr::DisplayListBuilder
& aBuilder
) {
30 aBuilder
.PushRect(mBounds
, mBounds
, true, true, false, mColor
);
34 bool WebRenderUserData::SupportsAsyncUpdate(nsIFrame
* aFrame
) {
38 RefPtr
<WebRenderImageData
> data
= GetWebRenderUserData
<WebRenderImageData
>(
39 aFrame
, static_cast<uint32_t>(DisplayItemType::TYPE_VIDEO
));
41 return data
->IsAsync();
48 bool WebRenderUserData::ProcessInvalidateForImage(nsIFrame
* aFrame
,
49 DisplayItemType aType
,
50 ImageProviderId aProviderId
) {
53 if (!aFrame
->HasProperty(WebRenderUserDataProperty::Key())) {
54 aFrame
->SchedulePaint();
58 auto type
= static_cast<uint32_t>(aType
);
59 RefPtr
<WebRenderFallbackData
> fallback
=
60 GetWebRenderUserData
<WebRenderFallbackData
>(aFrame
, type
);
62 fallback
->SetInvalid(true);
63 aFrame
->SchedulePaint();
67 RefPtr
<WebRenderImageProviderData
> image
=
68 GetWebRenderUserData
<WebRenderImageProviderData
>(aFrame
, type
);
69 if (image
&& image
->Invalidate(aProviderId
)) {
73 aFrame
->SchedulePaint();
77 WebRenderUserData::WebRenderUserData(RenderRootStateManager
* aManager
,
78 uint32_t aDisplayItemKey
, nsIFrame
* aFrame
)
81 mDisplayItemKey(aDisplayItemKey
),
82 mTable(aManager
->GetWebRenderUserDataTable()),
85 WebRenderUserData::WebRenderUserData(RenderRootStateManager
* aManager
,
88 mFrame(aItem
->Frame()),
89 mDisplayItemKey(aItem
->GetPerFrameKey()),
90 mTable(aManager
->GetWebRenderUserDataTable()),
93 WebRenderUserData::~WebRenderUserData() = default;
95 void WebRenderUserData::RemoveFromTable() { mTable
->Remove(this); }
97 WebRenderBridgeChild
* WebRenderUserData::WrBridge() const {
98 return mManager
->WrBridge();
101 WebRenderImageData::WebRenderImageData(RenderRootStateManager
* aManager
,
102 nsDisplayItem
* aItem
)
103 : WebRenderUserData(aManager
, aItem
) {}
105 WebRenderImageData::WebRenderImageData(RenderRootStateManager
* aManager
,
106 uint32_t aDisplayItemKey
,
108 : WebRenderUserData(aManager
, aDisplayItemKey
, aFrame
) {}
110 WebRenderImageData::~WebRenderImageData() {
114 mManager
->RemovePipelineIdForCompositable(mPipelineId
.ref());
118 void WebRenderImageData::ClearImageKey() {
120 mManager
->AddImageKeyForDiscard(mKey
.value());
121 if (mTextureOfImage
) {
122 WrBridge()->ReleaseTextureOfImage(mKey
.value());
123 mTextureOfImage
= nullptr;
127 MOZ_ASSERT(!mTextureOfImage
);
130 Maybe
<wr::ImageKey
> WebRenderImageData::UpdateImageKey(
131 ImageContainer
* aContainer
, wr::IpcResourceUpdateQueue
& aResources
,
133 MOZ_ASSERT(aContainer
);
135 if (mContainer
!= aContainer
) {
136 mContainer
= aContainer
;
139 CreateImageClientIfNeeded();
144 MOZ_ASSERT(mImageClient
->AsImageClientSingle());
146 ImageClientSingle
* imageClient
= mImageClient
->AsImageClientSingle();
147 uint32_t oldCounter
= imageClient
->GetLastUpdateGenerationCounter();
149 bool ret
= imageClient
->UpdateImage(aContainer
);
150 RefPtr
<TextureClient
> currentTexture
= imageClient
->GetForwardedTexture();
151 if (!ret
|| !currentTexture
) {
157 // Reuse old key if generation is not updated.
159 oldCounter
== imageClient
->GetLastUpdateGenerationCounter() && mKey
) {
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();
169 wr::MaybeExternalImageId extId
= currentTexture
->GetExternalImageKey();
170 MOZ_RELEASE_ASSERT(extId
.isSome());
173 MOZ_ASSERT(mKey
.isSome());
174 MOZ_ASSERT(mTextureOfImage
);
175 aResources
.PushExternalImageForTexture(
176 extId
.ref(), mKey
.ref(), currentTexture
, /* aIsUpdate */ true);
179 wr::WrImageKey key
= WrBridge()->GetNextImageKey();
180 aResources
.PushExternalImageForTexture(extId
.ref(), key
, currentTexture
,
181 /* aIsUpdate */ false);
185 mTextureOfImage
= currentTexture
;
189 already_AddRefed
<ImageClient
> WebRenderImageData::GetImageClient() {
190 RefPtr
<ImageClient
> imageClient
= mImageClient
;
191 return imageClient
.forget();
194 void WebRenderImageData::CreateAsyncImageWebRenderCommands(
195 mozilla::wr::DisplayListBuilder
& aBuilder
, ImageContainer
* aContainer
,
196 const StackingContextHelper
& aSc
, const LayoutDeviceRect
& aBounds
,
197 const LayoutDeviceRect
& aSCBounds
, VideoInfo::Rotation aRotation
,
198 const wr::ImageRendering
& aFilter
, const wr::MixBlendMode
& aMixBlendMode
,
199 bool aIsBackfaceVisible
) {
200 MOZ_ASSERT(aContainer
->IsAsync());
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());
210 // Alloc async image pipeline id.
212 Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
213 WrBridge()->AddPipelineIdForCompositable(
214 mPipelineId
.ref(), aContainer
->GetAsyncContainerHandle(),
215 CompositableHandleOwner::ImageBridge
);
216 mContainer
= aContainer
;
218 MOZ_ASSERT(!mImageClient
);
220 // Push IFrame for async image pipeline.
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);
231 WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(
232 mPipelineId
.value(), aSCBounds
, aRotation
, aFilter
, aMixBlendMode
));
235 void WebRenderImageData::CreateImageClientIfNeeded() {
237 mImageClient
= ImageClient::CreateImageClient(
238 CompositableType::IMAGE
, WrBridge(), TextureFlags::DEFAULT
);
243 mImageClient
->Connect();
247 WebRenderImageProviderData::WebRenderImageProviderData(
248 RenderRootStateManager
* aManager
, nsDisplayItem
* aItem
)
249 : WebRenderUserData(aManager
, aItem
) {}
251 WebRenderImageProviderData::WebRenderImageProviderData(
252 RenderRootStateManager
* aManager
, uint32_t aDisplayItemKey
,
254 : WebRenderUserData(aManager
, aDisplayItemKey
, aFrame
) {}
256 WebRenderImageProviderData::~WebRenderImageProviderData() = default;
258 Maybe
<wr::ImageKey
> WebRenderImageProviderData::UpdateImageKey(
259 WebRenderImageProvider
* aProvider
, ImgDrawResult aDrawResult
,
260 wr::IpcResourceUpdateQueue
& aResources
) {
261 if (mProvider
!= aProvider
) {
262 mProvider
= aProvider
;
265 wr::ImageKey key
= {};
266 nsresult rv
= mProvider
? mProvider
->UpdateKey(mManager
, aResources
, key
)
268 mKey
= NS_SUCCEEDED(rv
) ? Some(key
) : Nothing();
269 mDrawResult
= aDrawResult
;
273 bool WebRenderImageProviderData::Invalidate(ImageProviderId aProviderId
) const {
274 if (!aProviderId
|| !mProvider
|| mProvider
->GetProviderId() != aProviderId
||
279 if (mDrawResult
!= ImgDrawResult::SUCCESS
&&
280 mDrawResult
!= ImgDrawResult::BAD_IMAGE
) {
284 wr::ImageKey key
= {};
286 mProvider
->UpdateKey(mManager
, mManager
->AsyncResourceUpdates(), key
);
287 return NS_SUCCEEDED(rv
) && mKey
.ref() == key
;
290 WebRenderFallbackData::WebRenderFallbackData(RenderRootStateManager
* aManager
,
291 nsDisplayItem
* aItem
)
292 : WebRenderUserData(aManager
, aItem
), mOpacity(1.0f
), mInvalid(false) {}
294 WebRenderFallbackData::~WebRenderFallbackData() { ClearImageKey(); }
296 void WebRenderFallbackData::SetBlobImageKey(const wr::BlobImageKey
& aKey
) {
298 mBlobKey
= Some(aKey
);
301 Maybe
<wr::ImageKey
> WebRenderFallbackData::GetImageKey() {
303 return Some(wr::AsImageKey(mBlobKey
.value()));
307 return mImageData
->GetImageKey();
313 void WebRenderFallbackData::ClearImageKey() {
315 mImageData
->ClearImageKey();
316 mImageData
= nullptr;
320 mManager
->AddBlobImageKeyForDiscard(mBlobKey
.value());
325 WebRenderImageData
* WebRenderFallbackData::PaintIntoImage() {
327 mManager
->AddBlobImageKeyForDiscard(mBlobKey
.value());
332 return mImageData
.get();
335 mImageData
= MakeAndAddRef
<WebRenderImageData
>(mManager
.get(),
336 mDisplayItemKey
, mFrame
);
338 return mImageData
.get();
341 WebRenderAPZAnimationData::WebRenderAPZAnimationData(
342 RenderRootStateManager
* aManager
, nsDisplayItem
* aItem
)
343 : WebRenderUserData(aManager
, aItem
),
344 mAnimationId(AnimationHelper::GetNextCompositorAnimationsId()) {}
346 WebRenderAnimationData::WebRenderAnimationData(RenderRootStateManager
* aManager
,
347 nsDisplayItem
* aItem
)
348 : WebRenderUserData(aManager
, aItem
) {}
350 WebRenderAnimationData::~WebRenderAnimationData() {
351 // It may be the case that nsDisplayItem that created this WebRenderUserData
352 // gets destroyed without getting a chance to discard the compositor animation
353 // id, so we should do it as part of cleanup here.
354 uint64_t animationId
= mAnimationInfo
.GetCompositorAnimationsId();
355 // animationId might be 0 if mAnimationInfo never held any active animations.
357 mManager
->AddCompositorAnimationsIdForDiscard(animationId
);
361 WebRenderCanvasData::WebRenderCanvasData(RenderRootStateManager
* aManager
,
362 nsDisplayItem
* aItem
)
363 : WebRenderUserData(aManager
, aItem
) {}
365 WebRenderCanvasData::~WebRenderCanvasData() {
366 if (mCanvasRenderer
) {
367 mCanvasRenderer
->ClearCachedResources();
371 void WebRenderCanvasData::ClearCanvasRenderer() { mCanvasRenderer
= nullptr; }
373 WebRenderCanvasRendererAsync
* WebRenderCanvasData::GetCanvasRenderer() {
374 return mCanvasRenderer
.get();
377 WebRenderCanvasRendererAsync
* WebRenderCanvasData::CreateCanvasRenderer() {
378 mCanvasRenderer
= new WebRenderCanvasRendererAsync(mManager
);
379 return mCanvasRenderer
.get();
382 bool WebRenderCanvasData::SetCanvasRenderer(CanvasRenderer
* aCanvasRenderer
) {
383 if (!aCanvasRenderer
|| !aCanvasRenderer
->AsWebRenderCanvasRendererAsync()) {
387 auto* renderer
= aCanvasRenderer
->AsWebRenderCanvasRendererAsync();
388 if (mManager
!= renderer
->GetRenderRootStateManager()) {
392 mCanvasRenderer
= renderer
;
396 void WebRenderCanvasData::SetImageContainer(ImageContainer
* aImageContainer
) {
397 mContainer
= aImageContainer
;
400 ImageContainer
* WebRenderCanvasData::GetImageContainer() {
402 mContainer
= MakeAndAddRef
<ImageContainer
>();
407 void WebRenderCanvasData::ClearImageContainer() { mContainer
= nullptr; }
409 WebRenderRemoteData::WebRenderRemoteData(RenderRootStateManager
* aManager
,
410 nsDisplayItem
* aItem
)
411 : WebRenderUserData(aManager
, aItem
) {}
413 WebRenderRemoteData::~WebRenderRemoteData() {
414 if (mRemoteBrowser
) {
415 mRemoteBrowser
->UpdateEffects(mozilla::dom::EffectsInfo::FullyHidden());
419 void DestroyWebRenderUserDataTable(WebRenderUserDataTable
* aTable
) {
420 for (const auto& value
: aTable
->Values()) {
421 value
->RemoveFromTable();
426 } // namespace layers
427 } // namespace mozilla