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 "WebRenderImageHost.h"
7 :
8 : #include "LayersLogging.h"
9 : #include "mozilla/layers/Compositor.h" // for Compositor
10 : #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
11 : #include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
12 : #include "mozilla/layers/WebRenderBridgeParent.h"
13 : #include "mozilla/layers/WebRenderCompositableHolder.h"
14 : #include "nsAString.h"
15 : #include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
16 : #include "nsPrintfCString.h" // for nsPrintfCString
17 : #include "nsString.h" // for nsAutoCString
18 :
19 : namespace mozilla {
20 :
21 : using namespace gfx;
22 :
23 : namespace layers {
24 :
25 : class ISurfaceAllocator;
26 :
27 0 : WebRenderImageHost::WebRenderImageHost(const TextureInfo& aTextureInfo)
28 : : CompositableHost(aTextureInfo)
29 : , ImageComposite()
30 : , mWrBridge(nullptr)
31 0 : , mWrBridgeBindings(0)
32 0 : {}
33 :
34 0 : WebRenderImageHost::~WebRenderImageHost()
35 : {
36 0 : MOZ_ASSERT(!mWrBridge);
37 0 : }
38 :
39 : void
40 0 : WebRenderImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
41 : {
42 0 : CompositableHost::UseTextureHost(aTextures);
43 0 : MOZ_ASSERT(aTextures.Length() >= 1);
44 :
45 0 : nsTArray<TimedImage> newImages;
46 :
47 0 : for (uint32_t i = 0; i < aTextures.Length(); ++i) {
48 0 : const TimedTexture& t = aTextures[i];
49 0 : MOZ_ASSERT(t.mTexture);
50 0 : if (i + 1 < aTextures.Length() &&
51 0 : t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
52 : // Ignore frames before a frame that we already composited. We don't
53 : // ever want to display these frames. This could be important if
54 : // the frame producer adjusts timestamps (e.g. to track the audio clock)
55 : // and the new frame times are earlier.
56 0 : continue;
57 : }
58 0 : TimedImage& img = *newImages.AppendElement();
59 0 : img.mTextureHost = t.mTexture;
60 0 : img.mTimeStamp = t.mTimeStamp;
61 0 : img.mPictureRect = t.mPictureRect;
62 0 : img.mFrameID = t.mFrameID;
63 0 : img.mProducerID = t.mProducerID;
64 0 : img.mTextureHost->SetCropRect(img.mPictureRect);
65 0 : img.mTextureHost->Updated();
66 : }
67 :
68 0 : mImages.SwapElements(newImages);
69 0 : newImages.Clear();
70 :
71 0 : if (mWrBridge && GetAsyncRef()) {
72 0 : mWrBridge->ScheduleComposition();
73 : }
74 :
75 : // Video producers generally send replacement images with the same frameID but
76 : // slightly different timestamps in order to sync with the audio clock. This
77 : // means that any CompositeUntil() call we made in Composite() may no longer
78 : // guarantee that we'll composite until the next frame is ready. Fix that here.
79 0 : if (mWrBridge && mLastFrameID >= 0) {
80 0 : MOZ_ASSERT(mWrBridge->CompositableHolder());
81 0 : for (size_t i = 0; i < mImages.Length(); ++i) {
82 0 : bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
83 0 : mImages[i].mProducerID != mLastProducerID;
84 0 : if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
85 0 : mWrBridge->CompositableHolder()->CompositeUntil(mImages[i].mTimeStamp +
86 0 : TimeDuration::FromMilliseconds(BIAS_TIME_MS));
87 0 : break;
88 : }
89 : }
90 : }
91 0 : }
92 :
93 : void
94 0 : WebRenderImageHost::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
95 : TextureHost* aTextureOnWhite)
96 : {
97 0 : MOZ_ASSERT_UNREACHABLE("unexpected to be called");
98 : }
99 :
100 : void
101 0 : WebRenderImageHost::CleanupResources()
102 : {
103 0 : nsTArray<TimedImage> newImages;
104 0 : mImages.SwapElements(newImages);
105 0 : newImages.Clear();
106 0 : SetCurrentTextureHost(nullptr);
107 0 : }
108 :
109 : void
110 0 : WebRenderImageHost::RemoveTextureHost(TextureHost* aTexture)
111 : {
112 0 : CompositableHost::RemoveTextureHost(aTexture);
113 :
114 0 : for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
115 0 : if (mImages[i].mTextureHost == aTexture) {
116 0 : aTexture->UnbindTextureSource();
117 0 : mImages.RemoveElementAt(i);
118 : }
119 : }
120 0 : }
121 :
122 : TimeStamp
123 0 : WebRenderImageHost::GetCompositionTime() const
124 : {
125 0 : TimeStamp time;
126 0 : if (mWrBridge) {
127 0 : MOZ_ASSERT(mWrBridge->CompositableHolder());
128 0 : time = mWrBridge->CompositableHolder()->GetCompositionTime();
129 : }
130 0 : return time;
131 : }
132 :
133 : TextureHost*
134 0 : WebRenderImageHost::GetAsTextureHost(IntRect* aPictureRect)
135 : {
136 0 : TimedImage* img = ChooseImage();
137 0 : if (img) {
138 0 : return img->mTextureHost;
139 : }
140 0 : return nullptr;
141 : }
142 :
143 : TextureHost*
144 0 : WebRenderImageHost::GetAsTextureHostForComposite()
145 : {
146 0 : int imageIndex = ChooseImageIndex();
147 0 : if (imageIndex < 0) {
148 0 : SetCurrentTextureHost(nullptr);
149 0 : return nullptr;
150 : }
151 :
152 0 : if (mWrBridge && uint32_t(imageIndex) + 1 < mImages.Length()) {
153 0 : MOZ_ASSERT(mWrBridge->CompositableHolder());
154 0 : mWrBridge->CompositableHolder()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
155 : }
156 :
157 0 : TimedImage* img = &mImages[imageIndex];
158 :
159 0 : if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
160 0 : mLastFrameID = img->mFrameID;
161 0 : mLastProducerID = img->mProducerID;
162 : }
163 0 : SetCurrentTextureHost(img->mTextureHost);
164 0 : return mCurrentTextureHost;
165 : }
166 :
167 : void
168 0 : WebRenderImageHost::SetCurrentTextureHost(TextureHost* aTexture)
169 : {
170 0 : if (aTexture == mCurrentTextureHost.get()) {
171 0 : return;
172 : }
173 :
174 0 : if (mWrBridge &&
175 0 : !!mCurrentTextureHost &&
176 0 : mCurrentTextureHost != aTexture &&
177 0 : mCurrentTextureHost->AsWebRenderTextureHost()) {
178 0 : MOZ_ASSERT(mWrBridge->CompositableHolder());
179 0 : wr::PipelineId piplineId = mWrBridge->PipelineId();
180 0 : wr::Epoch epoch = mWrBridge->WrEpoch();
181 0 : mWrBridge->CompositableHolder()->HoldExternalImage(
182 : piplineId,
183 : epoch,
184 0 : mCurrentTextureHost->AsWebRenderTextureHost());
185 : }
186 :
187 0 : mCurrentTextureHost = aTexture;
188 : }
189 :
190 0 : void WebRenderImageHost::Attach(Layer* aLayer,
191 : TextureSourceProvider* aProvider,
192 : AttachFlags aFlags)
193 : {
194 0 : MOZ_ASSERT_UNREACHABLE("unexpected to be called");
195 : }
196 :
197 : void
198 0 : WebRenderImageHost::Composite(Compositor* aCompositor,
199 : LayerComposite* aLayer,
200 : EffectChain& aEffectChain,
201 : float aOpacity,
202 : const gfx::Matrix4x4& aTransform,
203 : const gfx::SamplingFilter aSamplingFilter,
204 : const gfx::IntRect& aClipRect,
205 : const nsIntRegion* aVisibleRegion,
206 : const Maybe<gfx::Polygon>& aGeometry)
207 : {
208 0 : MOZ_ASSERT_UNREACHABLE("unexpected to be called");
209 : }
210 :
211 : void
212 0 : WebRenderImageHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
213 : {
214 0 : if (mTextureSourceProvider != aProvider) {
215 0 : for (auto& img : mImages) {
216 0 : img.mTextureHost->SetTextureSourceProvider(aProvider);
217 : }
218 : }
219 0 : CompositableHost::SetTextureSourceProvider(aProvider);
220 0 : }
221 :
222 : void
223 0 : WebRenderImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
224 : {
225 0 : aStream << aPrefix;
226 0 : aStream << nsPrintfCString("WebRenderImageHost (0x%p)", this).get();
227 :
228 0 : nsAutoCString pfx(aPrefix);
229 0 : pfx += " ";
230 0 : for (auto& img : mImages) {
231 0 : aStream << "\n";
232 0 : img.mTextureHost->PrintInfo(aStream, pfx.get());
233 0 : AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
234 : }
235 0 : }
236 :
237 : void
238 0 : WebRenderImageHost::Dump(std::stringstream& aStream,
239 : const char* aPrefix,
240 : bool aDumpHtml)
241 : {
242 0 : for (auto& img : mImages) {
243 0 : aStream << aPrefix;
244 : aStream << (aDumpHtml ? "<ul><li>TextureHost: "
245 0 : : "TextureHost: ");
246 0 : DumpTextureHost(aStream, img.mTextureHost);
247 0 : aStream << (aDumpHtml ? " </li></ul> " : " ");
248 : }
249 0 : }
250 :
251 : already_AddRefed<gfx::DataSourceSurface>
252 0 : WebRenderImageHost::GetAsSurface()
253 : {
254 0 : TimedImage* img = ChooseImage();
255 0 : if (img) {
256 0 : return img->mTextureHost->GetAsSurface();
257 : }
258 0 : return nullptr;
259 : }
260 :
261 : bool
262 0 : WebRenderImageHost::Lock()
263 : {
264 0 : MOZ_ASSERT_UNREACHABLE("unexpected to be called");
265 : return false;
266 : }
267 :
268 : void
269 0 : WebRenderImageHost::Unlock()
270 : {
271 0 : MOZ_ASSERT_UNREACHABLE("unexpected to be called");
272 : }
273 :
274 : IntSize
275 0 : WebRenderImageHost::GetImageSize() const
276 : {
277 0 : const TimedImage* img = ChooseImage();
278 0 : if (img) {
279 0 : return IntSize(img->mPictureRect.width, img->mPictureRect.height);
280 : }
281 0 : return IntSize();
282 : }
283 :
284 : void
285 0 : WebRenderImageHost::SetWrBridge(WebRenderBridgeParent* aWrBridge)
286 : {
287 : // For image hosts created through ImageBridgeParent, there may be multiple
288 : // references to it due to the order of creation and freeing of layers by
289 : // the layer tree. However this should be limited to things such as video
290 : // which will not be reused across different WebRenderBridgeParent objects.
291 0 : MOZ_ASSERT(aWrBridge);
292 0 : MOZ_ASSERT(!mWrBridge || mWrBridge == aWrBridge);
293 0 : mWrBridge = aWrBridge;
294 0 : ++mWrBridgeBindings;
295 0 : }
296 :
297 : void
298 0 : WebRenderImageHost::ClearWrBridge()
299 : {
300 0 : MOZ_ASSERT(mWrBridgeBindings > 0);
301 0 : --mWrBridgeBindings;
302 0 : if (mWrBridgeBindings == 0) {
303 0 : SetCurrentTextureHost(nullptr);
304 0 : mWrBridge = nullptr;
305 : }
306 0 : }
307 :
308 : } // namespace layers
309 : } // namespace mozilla
|