Line data Source code
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 "WebRenderCompositableHolder.h"
7 :
8 : #include "CompositableHost.h"
9 : #include "mozilla/gfx/gfxVars.h"
10 : #include "mozilla/layers/WebRenderImageHost.h"
11 : #include "mozilla/layers/WebRenderTextureHost.h"
12 : #include "mozilla/webrender/WebRenderAPI.h"
13 :
14 : namespace mozilla {
15 : namespace layers {
16 :
17 0 : WebRenderCompositableHolder::AsyncImagePipelineHolder::AsyncImagePipelineHolder()
18 : : mInitialised(false)
19 : , mIsChanged(false)
20 : , mUseExternalImage(false)
21 : , mFilter(WrImageRendering::Auto)
22 0 : , mMixBlendMode(WrMixBlendMode::Normal)
23 0 : {}
24 :
25 0 : WebRenderCompositableHolder::WebRenderCompositableHolder(uint32_t aIdNamespace)
26 : : mIdNamespace(aIdNamespace)
27 : , mResourceId(0)
28 : , mAsyncImageEpoch(0)
29 0 : , mDestroyed(false)
30 : {
31 0 : MOZ_COUNT_CTOR(WebRenderCompositableHolder);
32 0 : }
33 :
34 0 : WebRenderCompositableHolder::~WebRenderCompositableHolder()
35 : {
36 0 : MOZ_COUNT_DTOR(WebRenderCompositableHolder);
37 0 : }
38 :
39 : void
40 0 : WebRenderCompositableHolder::Destroy(wr::WebRenderAPI* aApi)
41 : {
42 0 : DeleteOldAsyncImages(aApi);
43 0 : mDestroyed = true;
44 0 : }
45 :
46 : bool
47 0 : WebRenderCompositableHolder::HasKeysToDelete()
48 : {
49 0 : return !mKeysToDelete.IsEmpty();
50 : }
51 :
52 : void
53 0 : WebRenderCompositableHolder::DeleteOldAsyncImages(wr::WebRenderAPI* aApi)
54 : {
55 0 : for (wr::ImageKey key : mKeysToDelete) {
56 0 : aApi->DeleteImage(key);
57 : }
58 0 : mKeysToDelete.Clear();
59 0 : }
60 :
61 : void
62 0 : WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId)
63 : {
64 0 : if (mDestroyed) {
65 0 : return;
66 : }
67 0 : uint64_t id = wr::AsUint64(aPipelineId);
68 :
69 0 : PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
70 0 : if(holder) {
71 : // This could happen during tab move between different windows.
72 : // Previously removed holder could be still alive for waiting destroyed.
73 0 : MOZ_ASSERT(holder->mDestroyedEpoch.isSome());
74 0 : holder->mDestroyedEpoch = Nothing(); // Revive holder
75 0 : return;
76 : }
77 0 : holder = new PipelineTexturesHolder();
78 0 : mPipelineTexturesHolders.Put(id, holder);
79 : }
80 :
81 : void
82 0 : WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
83 : {
84 0 : if (mDestroyed) {
85 0 : return;
86 : }
87 :
88 0 : PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
89 0 : MOZ_ASSERT(holder);
90 0 : if (!holder) {
91 0 : return;
92 : }
93 0 : holder->mDestroyedEpoch = Some(aEpoch);
94 : }
95 :
96 : void
97 0 : WebRenderCompositableHolder::AddAsyncImagePipeline(const wr::PipelineId& aPipelineId, WebRenderImageHost* aImageHost)
98 : {
99 0 : if (mDestroyed) {
100 0 : return;
101 : }
102 0 : MOZ_ASSERT(aImageHost);
103 0 : uint64_t id = wr::AsUint64(aPipelineId);
104 :
105 0 : MOZ_ASSERT(!mAsyncImagePipelineHolders.Get(id));
106 0 : AsyncImagePipelineHolder* holder = new AsyncImagePipelineHolder();
107 0 : holder->mImageHost = aImageHost;
108 0 : mAsyncImagePipelineHolders.Put(id, holder);
109 0 : AddPipeline(aPipelineId);
110 : }
111 :
112 : void
113 0 : WebRenderCompositableHolder::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId)
114 : {
115 0 : if (mDestroyed) {
116 0 : return;
117 : }
118 :
119 0 : uint64_t id = wr::AsUint64(aPipelineId);
120 0 : if (auto entry = mAsyncImagePipelineHolders.Lookup(id)) {
121 0 : AsyncImagePipelineHolder* holder = entry.Data();
122 0 : ++mAsyncImageEpoch; // Update webrender epoch
123 0 : aApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
124 0 : for (wr::ImageKey key : holder->mKeys) {
125 0 : aApi->DeleteImage(key);
126 : }
127 0 : entry.Remove();
128 0 : RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
129 : }
130 : }
131 :
132 : void
133 0 : WebRenderCompositableHolder::UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
134 : const LayerRect& aScBounds,
135 : const gfx::Matrix4x4& aScTransform,
136 : const gfx::MaybeIntSize& aScaleToSize,
137 : const WrImageRendering& aFilter,
138 : const WrMixBlendMode& aMixBlendMode)
139 : {
140 0 : if (mDestroyed) {
141 0 : return;
142 : }
143 0 : AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(wr::AsUint64(aPipelineId));
144 0 : if (!holder) {
145 0 : return;
146 : }
147 0 : holder->mInitialised = true;
148 0 : holder->mIsChanged = true;
149 0 : holder->mScBounds = aScBounds;
150 0 : holder->mScTransform = aScTransform;
151 0 : holder->mScaleToSize = aScaleToSize;
152 0 : holder->mFilter = aFilter;
153 0 : holder->mMixBlendMode = aMixBlendMode;
154 : }
155 :
156 : bool
157 0 : WebRenderCompositableHolder::GetImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
158 : {
159 0 : MOZ_ASSERT(aKeys.IsEmpty());
160 0 : MOZ_ASSERT(aTexture);
161 :
162 0 : WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
163 :
164 0 : if (wrTexture) {
165 0 : wrTexture->GetWRImageKeys(aKeys, std::bind(&WebRenderCompositableHolder::GetImageKey, this));
166 0 : MOZ_ASSERT(!aKeys.IsEmpty());
167 0 : Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
168 0 : wrTexture->AddWRImage(aApi, keys, wrTexture->GetExternalImageKey());
169 0 : return true;
170 : } else {
171 0 : RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
172 0 : if (!dSurf) {
173 0 : NS_ERROR("TextureHost does not return DataSourceSurface");
174 0 : return false;
175 : }
176 : gfx::DataSourceSurface::MappedSurface map;
177 0 : if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
178 0 : NS_ERROR("DataSourceSurface failed to map");
179 0 : return false;
180 : }
181 0 : gfx::IntSize size = dSurf->GetSize();
182 0 : wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
183 0 : auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
184 :
185 0 : wr::ImageKey key = GetImageKey();
186 0 : aKeys.AppendElement(key);
187 0 : aApi->AddImage(key, descriptor, slice);
188 0 : dSurf->Unmap();
189 : }
190 0 : return false;
191 : }
192 :
193 : bool
194 0 : WebRenderCompositableHolder::UpdateImageKeys(wr::WebRenderAPI* aApi,
195 : bool& aUseExternalImage,
196 : AsyncImagePipelineHolder* aHolder,
197 : nsTArray<wr::ImageKey>& aKeys,
198 : nsTArray<wr::ImageKey>& aKeysToDelete)
199 : {
200 0 : MOZ_ASSERT(aKeys.IsEmpty());
201 0 : MOZ_ASSERT(aHolder);
202 0 : TextureHost* texture = aHolder->mImageHost->GetAsTextureHostForComposite();
203 :
204 0 : if (!aHolder->mInitialised) {
205 0 : return false;
206 : }
207 :
208 : // No change
209 0 : if (!aHolder->mIsChanged && texture == aHolder->mCurrentTexture) {
210 : // No need to update DisplayList.
211 0 : return false;
212 : }
213 :
214 0 : aHolder->mIsChanged = false;
215 :
216 0 : if (texture == aHolder->mCurrentTexture) {
217 : // Reuse previous ImageKeys.
218 0 : aKeys.AppendElements(aHolder->mKeys);
219 0 : aUseExternalImage = aHolder->mUseExternalImage;
220 0 : return true;
221 : }
222 :
223 : // Delete old ImageKeys
224 0 : aKeysToDelete.AppendElements(aHolder->mKeys);
225 0 : aHolder->mKeys.Clear();
226 0 : aHolder->mCurrentTexture = nullptr;
227 :
228 : // No txture to render
229 0 : if (!texture) {
230 0 : return true;
231 : }
232 :
233 0 : aUseExternalImage = aHolder->mUseExternalImage = GetImageKeyForTextureHost(aApi, texture, aKeys);
234 0 : MOZ_ASSERT(!aKeys.IsEmpty());
235 0 : aHolder->mKeys.AppendElements(aKeys);
236 0 : aHolder->mCurrentTexture = texture;
237 0 : return true;
238 : }
239 :
240 : void
241 0 : WebRenderCompositableHolder::ApplyAsyncImages(wr::WebRenderAPI* aApi)
242 : {
243 0 : if (mDestroyed || mAsyncImagePipelineHolders.Count() == 0) {
244 0 : return;
245 : }
246 :
247 0 : ++mAsyncImageEpoch; // Update webrender epoch
248 0 : wr::Epoch epoch = wr::NewEpoch(mAsyncImageEpoch);
249 0 : nsTArray<wr::ImageKey> keysToDelete;
250 :
251 0 : for (auto iter = mAsyncImagePipelineHolders.Iter(); !iter.Done(); iter.Next()) {
252 0 : wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
253 0 : AsyncImagePipelineHolder* holder = iter.Data();
254 :
255 0 : nsTArray<wr::ImageKey> keys;
256 0 : bool useExternalImage = false;
257 : bool updateDisplayList = UpdateImageKeys(aApi,
258 : useExternalImage,
259 : holder,
260 : keys,
261 0 : keysToDelete);
262 0 : if (!updateDisplayList) {
263 0 : continue;
264 : }
265 :
266 0 : WrSize contentSize { holder->mScBounds.width, holder->mScBounds.height };
267 0 : wr::DisplayListBuilder builder(pipelineId, contentSize);
268 :
269 0 : if (!keys.IsEmpty()) {
270 0 : MOZ_ASSERT(holder->mCurrentTexture.get());
271 :
272 0 : float opacity = 1.0f;
273 0 : builder.PushStackingContext(wr::ToWrRect(holder->mScBounds),
274 : 0,
275 : &opacity,
276 0 : holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
277 : WrTransformStyle::Flat,
278 : holder->mMixBlendMode,
279 0 : nsTArray<WrFilterOp>());
280 :
281 0 : LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height);
282 0 : if (holder->mScaleToSize.isSome()) {
283 0 : rect = LayerRect(0, 0, holder->mScaleToSize.value().width, holder->mScaleToSize.value().height);
284 : }
285 :
286 0 : if (useExternalImage) {
287 0 : MOZ_ASSERT(holder->mCurrentTexture->AsWebRenderTextureHost());
288 0 : Range<const wr::ImageKey> range_keys(&keys[0], keys.Length());
289 0 : holder->mCurrentTexture->PushExternalImage(builder,
290 0 : wr::ToWrRect(rect),
291 0 : wr::ToWrRect(rect),
292 : holder->mFilter,
293 0 : range_keys);
294 0 : HoldExternalImage(pipelineId, epoch, holder->mCurrentTexture->AsWebRenderTextureHost());
295 : } else {
296 0 : MOZ_ASSERT(keys.Length() == 1);
297 0 : builder.PushImage(wr::ToWrRect(rect),
298 0 : wr::ToWrRect(rect),
299 : holder->mFilter,
300 0 : keys[0]);
301 : }
302 0 : builder.PopStackingContext();
303 : }
304 :
305 0 : wr::BuiltDisplayList dl;
306 : WrSize builderContentSize;
307 0 : builder.Finalize(builderContentSize, dl);
308 0 : aApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(holder->mScBounds.width, holder->mScBounds.height),
309 : pipelineId, builderContentSize,
310 0 : dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
311 : }
312 0 : DeleteOldAsyncImages(aApi);
313 0 : mKeysToDelete.SwapElements(keysToDelete);
314 : }
315 :
316 : void
317 0 : WebRenderCompositableHolder::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
318 : {
319 0 : if (mDestroyed) {
320 0 : return;
321 : }
322 0 : MOZ_ASSERT(aTexture);
323 :
324 0 : PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
325 0 : MOZ_ASSERT(holder);
326 0 : if (!holder) {
327 0 : return;
328 : }
329 : // Hold WebRenderTextureHost until end of its usage on RenderThread
330 0 : holder->mTextureHosts.push(ForwardingTextureHost(aEpoch, aTexture));
331 : }
332 :
333 : void
334 0 : WebRenderCompositableHolder::Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
335 : {
336 0 : if (mDestroyed) {
337 0 : return;
338 : }
339 0 : if (auto entry = mPipelineTexturesHolders.Lookup(wr::AsUint64(aPipelineId))) {
340 0 : PipelineTexturesHolder* holder = entry.Data();
341 : // Remove Pipeline
342 0 : if (holder->mDestroyedEpoch.isSome() && holder->mDestroyedEpoch.ref() <= aEpoch) {
343 0 : entry.Remove();
344 0 : return;
345 : }
346 :
347 : // Release TextureHosts based on Epoch
348 0 : while (!holder->mTextureHosts.empty()) {
349 0 : if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
350 0 : break;
351 : }
352 0 : holder->mTextureHosts.pop();
353 : }
354 : }
355 : }
356 :
357 : } // namespace layers
358 : } // namespace mozilla
|