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 "GPUVideoTextureHost.h"
8 
9 #include "ImageContainer.h"
10 #include "mozilla/RemoteDecoderManagerParent.h"
11 #include "mozilla/layers/ImageBridgeParent.h"
12 #include "mozilla/layers/VideoBridgeParent.h"
13 #include "mozilla/webrender/RenderTextureHostWrapper.h"
14 #include "mozilla/webrender/RenderThread.h"
15 
16 namespace mozilla {
17 namespace layers {
18 
GPUVideoTextureHost(TextureFlags aFlags,const SurfaceDescriptorGPUVideo & aDescriptor)19 GPUVideoTextureHost::GPUVideoTextureHost(
20     TextureFlags aFlags, const SurfaceDescriptorGPUVideo& aDescriptor)
21     : TextureHost(aFlags), mDescriptor(aDescriptor) {
22   MOZ_COUNT_CTOR(GPUVideoTextureHost);
23 }
24 
~GPUVideoTextureHost()25 GPUVideoTextureHost::~GPUVideoTextureHost() {
26   MOZ_COUNT_DTOR(GPUVideoTextureHost);
27 }
28 
CreateFromDescriptor(TextureFlags aFlags,const SurfaceDescriptorGPUVideo & aDescriptor)29 GPUVideoTextureHost* GPUVideoTextureHost::CreateFromDescriptor(
30     TextureFlags aFlags, const SurfaceDescriptorGPUVideo& aDescriptor) {
31   return new GPUVideoTextureHost(aFlags, aDescriptor);
32 }
33 
EnsureWrappedTextureHost()34 TextureHost* GPUVideoTextureHost::EnsureWrappedTextureHost() {
35   if (mWrappedTextureHost) {
36     return mWrappedTextureHost;
37   }
38 
39   const auto& sd =
40       static_cast<const SurfaceDescriptorRemoteDecoder&>(mDescriptor);
41   VideoBridgeParent* parent = VideoBridgeParent::GetSingleton(sd.source());
42   if (!parent) {
43     // The VideoBridge went away. This can happen if the RDD process
44     // crashes.
45     return nullptr;
46   }
47   mWrappedTextureHost = parent->LookupTexture(sd.handle());
48 
49   if (!mWrappedTextureHost) {
50     // The TextureHost hasn't been registered yet. This is due to a race
51     // between the ImageBridge (content) and the VideoBridge (RDD) and the
52     // ImageBridge won. See bug
53     // https://bugzilla.mozilla.org/show_bug.cgi?id=1630733#c14 for more
54     // details.
55     return nullptr;
56   }
57 
58   if (mWrappedTextureHost->AsBufferTextureHost()) {
59     // TODO(miko): This code path is taken when WebRenderTextureHost wraps
60     // GPUVideoTextureHost, which wraps BufferTextureHost.
61     // Because this creates additional copies of the texture data, we should not
62     // do this.
63     mWrappedTextureHost->AsBufferTextureHost()->DisableExternalTextures();
64   }
65 
66   if (mExternalImageId.isSome()) {
67     // External image id is allocated by mWrappedTextureHost.
68     mWrappedTextureHost->EnsureRenderTexture(Nothing());
69     MOZ_ASSERT(mWrappedTextureHost->mExternalImageId.isSome());
70     auto wrappedId = mWrappedTextureHost->mExternalImageId.ref();
71 
72     RefPtr<wr::RenderTextureHost> texture =
73         new wr::RenderTextureHostWrapper(wrappedId);
74     wr::RenderThread::Get()->RegisterExternalImage(
75         wr::AsUint64(mExternalImageId.ref()), texture.forget());
76   }
77 
78   if (mPendingSourceProvider) {
79     RefPtr<TextureSourceProvider> provider = mPendingSourceProvider.forget();
80     mWrappedTextureHost->SetTextureSourceProvider(provider);
81   }
82   if (mPendingUpdatedInternal) {
83     mWrappedTextureHost->UpdatedInternal(mPendingIntRegion.ptrOr(nullptr));
84     mPendingIntRegion.reset();
85     mPendingUpdatedInternal = false;
86   }
87   if (mPendingPrepareTextureSource) {
88     mWrappedTextureHost->PrepareTextureSource(*mPendingPrepareTextureSource);
89     mPendingPrepareTextureSource.reset();
90   }
91 
92   return mWrappedTextureHost;
93 }
94 
IsValid()95 bool GPUVideoTextureHost::IsValid() { return !!EnsureWrappedTextureHost(); }
96 
Lock()97 bool GPUVideoTextureHost::Lock() {
98   if (!EnsureWrappedTextureHost()) {
99     return false;
100   }
101   return EnsureWrappedTextureHost()->Lock();
102 }
103 
Unlock()104 void GPUVideoTextureHost::Unlock() {
105   if (!EnsureWrappedTextureHost()) {
106     return;
107   }
108   EnsureWrappedTextureHost()->Unlock();
109 }
110 
PrepareTextureSource(CompositableTextureSourceRef & aTexture)111 void GPUVideoTextureHost::PrepareTextureSource(
112     CompositableTextureSourceRef& aTexture) {
113   if (!EnsureWrappedTextureHost()) {
114     mPendingPrepareTextureSource = Some(aTexture);
115     return;
116   }
117   EnsureWrappedTextureHost()->PrepareTextureSource(aTexture);
118 }
119 
BindTextureSource(CompositableTextureSourceRef & aTexture)120 bool GPUVideoTextureHost::BindTextureSource(
121     CompositableTextureSourceRef& aTexture) {
122   MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
123   if (!EnsureWrappedTextureHost()) {
124     return false;
125   }
126   return EnsureWrappedTextureHost()->BindTextureSource(aTexture);
127 }
128 
AcquireTextureSource(CompositableTextureSourceRef & aTexture)129 bool GPUVideoTextureHost::AcquireTextureSource(
130     CompositableTextureSourceRef& aTexture) {
131   MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
132   if (!EnsureWrappedTextureHost()) {
133     return false;
134   }
135   return EnsureWrappedTextureHost()->AcquireTextureSource(aTexture);
136 }
137 
SetTextureSourceProvider(TextureSourceProvider * aProvider)138 void GPUVideoTextureHost::SetTextureSourceProvider(
139     TextureSourceProvider* aProvider) {
140   if (!EnsureWrappedTextureHost()) {
141     mPendingSourceProvider = aProvider;
142     return;
143   }
144   EnsureWrappedTextureHost()->SetTextureSourceProvider(aProvider);
145 }
146 
GetYUVColorSpace() const147 gfx::YUVColorSpace GPUVideoTextureHost::GetYUVColorSpace() const {
148   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
149   if (!mWrappedTextureHost) {
150     return TextureHost::GetYUVColorSpace();
151   }
152   return mWrappedTextureHost->GetYUVColorSpace();
153 }
154 
GetColorDepth() const155 gfx::ColorDepth GPUVideoTextureHost::GetColorDepth() const {
156   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
157   if (!mWrappedTextureHost) {
158     return TextureHost::GetColorDepth();
159   }
160   return mWrappedTextureHost->GetColorDepth();
161 }
162 
GetColorRange() const163 gfx::ColorRange GPUVideoTextureHost::GetColorRange() const {
164   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
165   if (!mWrappedTextureHost) {
166     return TextureHost::GetColorRange();
167   }
168   return mWrappedTextureHost->GetColorRange();
169 }
170 
GetSize() const171 gfx::IntSize GPUVideoTextureHost::GetSize() const {
172   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
173   if (!mWrappedTextureHost) {
174     return gfx::IntSize();
175   }
176   return mWrappedTextureHost->GetSize();
177 }
178 
GetFormat() const179 gfx::SurfaceFormat GPUVideoTextureHost::GetFormat() const {
180   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
181   if (!mWrappedTextureHost) {
182     return gfx::SurfaceFormat::UNKNOWN;
183   }
184   return mWrappedTextureHost->GetFormat();
185 }
186 
HasIntermediateBuffer() const187 bool GPUVideoTextureHost::HasIntermediateBuffer() const {
188   MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
189   if (!mWrappedTextureHost) {
190     return false;
191   }
192   return mWrappedTextureHost->HasIntermediateBuffer();
193 }
194 
UpdatedInternal(const nsIntRegion * Region)195 void GPUVideoTextureHost::UpdatedInternal(const nsIntRegion* Region) {
196   if (!EnsureWrappedTextureHost()) {
197     mPendingUpdatedInternal = true;
198     if (Region) {
199       mPendingIntRegion = Some(*Region);
200     } else {
201       mPendingIntRegion.reset();
202     }
203     return;
204   }
205   EnsureWrappedTextureHost()->UpdatedInternal(Region);
206 }
207 
CreateRenderTexture(const wr::ExternalImageId & aExternalImageId)208 void GPUVideoTextureHost::CreateRenderTexture(
209     const wr::ExternalImageId& aExternalImageId) {
210   MOZ_ASSERT(mExternalImageId.isSome());
211 
212   // When mWrappedTextureHost already exist, call CreateRenderTexture() here.
213   // In other cases, EnsureWrappedTextureHost() handles CreateRenderTexture().
214 
215   if (mWrappedTextureHost) {
216     // External image id is allocated by mWrappedTextureHost.
217     mWrappedTextureHost->EnsureRenderTexture(Nothing());
218     MOZ_ASSERT(mWrappedTextureHost->mExternalImageId.isSome());
219     auto wrappedId = mWrappedTextureHost->mExternalImageId.ref();
220 
221     RefPtr<wr::RenderTextureHost> texture =
222         new wr::RenderTextureHostWrapper(wrappedId);
223     wr::RenderThread::Get()->RegisterExternalImage(
224         wr::AsUint64(mExternalImageId.ref()), texture.forget());
225     return;
226   }
227 
228   EnsureWrappedTextureHost();
229 }
230 
MaybeDestroyRenderTexture()231 void GPUVideoTextureHost::MaybeDestroyRenderTexture() {
232   if (mExternalImageId.isNothing() || !mWrappedTextureHost) {
233     // RenderTextureHost was not created
234     return;
235   }
236   // When GPUVideoTextureHost created RenderTextureHost, delete it here.
237   TextureHost::DestroyRenderTexture(mExternalImageId.ref());
238 }
239 
NumSubTextures()240 uint32_t GPUVideoTextureHost::NumSubTextures() {
241   if (!EnsureWrappedTextureHost()) {
242     return 0;
243   }
244   return EnsureWrappedTextureHost()->NumSubTextures();
245 }
246 
PushResourceUpdates(wr::TransactionBuilder & aResources,ResourceUpdateOp aOp,const Range<wr::ImageKey> & aImageKeys,const wr::ExternalImageId & aExtID)247 void GPUVideoTextureHost::PushResourceUpdates(
248     wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
249     const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
250   MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
251   if (!EnsureWrappedTextureHost()) {
252     return;
253   }
254   EnsureWrappedTextureHost()->PushResourceUpdates(aResources, aOp, aImageKeys,
255                                                   aExtID);
256 }
257 
PushDisplayItems(wr::DisplayListBuilder & aBuilder,const wr::LayoutRect & aBounds,const wr::LayoutRect & aClip,wr::ImageRendering aFilter,const Range<wr::ImageKey> & aImageKeys,PushDisplayItemFlagSet aFlags)258 void GPUVideoTextureHost::PushDisplayItems(
259     wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
260     const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
261     const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
262   MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
263   MOZ_ASSERT(aImageKeys.length() > 0);
264   if (!EnsureWrappedTextureHost()) {
265     return;
266   }
267 
268   EnsureWrappedTextureHost()->PushDisplayItems(aBuilder, aBounds, aClip,
269                                                aFilter, aImageKeys, aFlags);
270 }
271 
SupportsExternalCompositing(WebRenderBackend aBackend)272 bool GPUVideoTextureHost::SupportsExternalCompositing(
273     WebRenderBackend aBackend) {
274   if (!EnsureWrappedTextureHost()) {
275     return false;
276   }
277   return EnsureWrappedTextureHost()->SupportsExternalCompositing(aBackend);
278 }
279 
UnbindTextureSource()280 void GPUVideoTextureHost::UnbindTextureSource() {
281   if (EnsureWrappedTextureHost()) {
282     EnsureWrappedTextureHost()->UnbindTextureSource();
283   }
284   // Handle read unlock
285   TextureHost::UnbindTextureSource();
286 }
287 
NotifyNotUsed()288 void GPUVideoTextureHost::NotifyNotUsed() {
289   if (EnsureWrappedTextureHost()) {
290     EnsureWrappedTextureHost()->NotifyNotUsed();
291   }
292   TextureHost::NotifyNotUsed();
293 }
294 
295 }  // namespace layers
296 }  // namespace mozilla
297