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 "TextureHost.h"
8 
9 #include "CompositableHost.h"  // for CompositableHost
10 #include "LayerScope.h"
11 #include "LayersLogging.h"   // for AppendToString
12 #include "mozilla/gfx/2D.h"  // for DataSourceSurface, Factory
13 #include "mozilla/gfx/gfxVars.h"
14 #include "mozilla/ipc/Shmem.h"  // for Shmem
15 #include "mozilla/layers/AsyncImagePipelineManager.h"
16 #include "mozilla/layers/CompositableTransactionParent.h"  // for CompositableParentManager
17 #include "mozilla/layers/CompositorBridgeParent.h"
18 #include "mozilla/layers/Compositor.h"         // for Compositor
19 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
20 #include "mozilla/layers/ImageBridgeParent.h"  // for ImageBridgeParent
21 #include "mozilla/layers/LayersSurfaces.h"     // for SurfaceDescriptor, etc
22 #include "mozilla/layers/TextureHostBasic.h"
23 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
24 #include "mozilla/layers/ImageDataSerializer.h"
25 #include "mozilla/layers/TextureClient.h"
26 #ifdef XP_DARWIN
27 #  include "mozilla/layers/TextureSync.h"
28 #endif
29 #include "mozilla/layers/GPUVideoTextureHost.h"
30 #include "mozilla/layers/WebRenderTextureHost.h"
31 #include "mozilla/StaticPrefs_layers.h"
32 #include "mozilla/webrender/RenderBufferTextureHost.h"
33 #include "mozilla/webrender/RenderThread.h"
34 #include "mozilla/webrender/WebRenderAPI.h"
35 #include "nsAString.h"
36 #include "mozilla/RefPtr.h"   // for nsRefPtr
37 #include "nsPrintfCString.h"  // for nsPrintfCString
38 #include "mozilla/layers/PTextureParent.h"
39 #include "mozilla/Unused.h"
40 #include <limits>
41 #include "../opengl/CompositorOGL.h"
42 
43 #include "gfxUtils.h"
44 #include "IPDLActor.h"
45 
46 #ifdef MOZ_ENABLE_D3D10_LAYER
47 #  include "../d3d11/CompositorD3D11.h"
48 #endif
49 
50 #ifdef MOZ_X11
51 #  include "mozilla/layers/X11TextureHost.h"
52 #endif
53 
54 #ifdef XP_MACOSX
55 #  include "../opengl/MacIOSurfaceTextureHostOGL.h"
56 #endif
57 
58 #ifdef XP_WIN
59 #  include "mozilla/layers/TextureD3D11.h"
60 #  include "mozilla/layers/TextureDIB.h"
61 #endif
62 
63 #if 0
64 #  define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
65 #else
66 #  define RECYCLE_LOG(...) \
67     do {                   \
68     } while (0)
69 #endif
70 
71 namespace mozilla {
72 namespace layers {
73 
74 /**
75  * TextureParent is the host-side IPDL glue between TextureClient and
76  * TextureHost. It is an IPDL actor just like LayerParent, CompositableParent,
77  * etc.
78  */
79 class TextureParent : public ParentActor<PTextureParent> {
80  public:
81   TextureParent(HostIPCAllocator* aAllocator, uint64_t aSerial,
82                 const wr::MaybeExternalImageId& aExternalImageId);
83 
84   virtual ~TextureParent();
85 
86   bool Init(const SurfaceDescriptor& aSharedData,
87             const ReadLockDescriptor& aReadLock,
88             const LayersBackend& aLayersBackend, const TextureFlags& aFlags);
89 
90   void NotifyNotUsed(uint64_t aTransactionId);
91 
92   mozilla::ipc::IPCResult RecvRecycleTexture(
93       const TextureFlags& aTextureFlags) final;
94 
GetTextureHost()95   TextureHost* GetTextureHost() { return mTextureHost; }
96 
97   void Destroy() override;
98 
GetSerial() const99   uint64_t GetSerial() const { return mSerial; }
100 
101   HostIPCAllocator* mSurfaceAllocator;
102   RefPtr<TextureHost> mTextureHost;
103   // mSerial is unique in TextureClient's process.
104   const uint64_t mSerial;
105   wr::MaybeExternalImageId mExternalImageId;
106 };
107 
WrapWithWebRenderTextureHost(ISurfaceAllocator * aDeallocator,LayersBackend aBackend,TextureFlags aFlags)108 static bool WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
109                                          LayersBackend aBackend,
110                                          TextureFlags aFlags) {
111   if ((aFlags & TextureFlags::SNAPSHOT) ||
112       (aBackend != LayersBackend::LAYERS_WR) ||
113       (!aDeallocator->UsesImageBridge() &&
114        !aDeallocator->AsCompositorBridgeParentBase())) {
115     return false;
116   }
117   return true;
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
CreateIPDLActor(HostIPCAllocator * aAllocator,const SurfaceDescriptor & aSharedData,const ReadLockDescriptor & aReadLock,LayersBackend aLayersBackend,TextureFlags aFlags,uint64_t aSerial,const wr::MaybeExternalImageId & aExternalImageId)121 PTextureParent* TextureHost::CreateIPDLActor(
122     HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData,
123     const ReadLockDescriptor& aReadLock, LayersBackend aLayersBackend,
124     TextureFlags aFlags, uint64_t aSerial,
125     const wr::MaybeExternalImageId& aExternalImageId) {
126   TextureParent* actor =
127       new TextureParent(aAllocator, aSerial, aExternalImageId);
128   if (!actor->Init(aSharedData, aReadLock, aLayersBackend, aFlags)) {
129     actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
130     delete actor;
131     return nullptr;
132   }
133   return actor;
134 }
135 
136 // static
DestroyIPDLActor(PTextureParent * actor)137 bool TextureHost::DestroyIPDLActor(PTextureParent* actor) {
138   delete actor;
139   return true;
140 }
141 
142 // static
SendDeleteIPDLActor(PTextureParent * actor)143 bool TextureHost::SendDeleteIPDLActor(PTextureParent* actor) {
144   return PTextureParent::Send__delete__(actor);
145 }
146 
147 // static
AsTextureHost(PTextureParent * actor)148 TextureHost* TextureHost::AsTextureHost(PTextureParent* actor) {
149   if (!actor) {
150     return nullptr;
151   }
152   return static_cast<TextureParent*>(actor)->mTextureHost;
153 }
154 
155 // static
GetTextureSerial(PTextureParent * actor)156 uint64_t TextureHost::GetTextureSerial(PTextureParent* actor) {
157   if (!actor) {
158     return UINT64_MAX;
159   }
160   return static_cast<TextureParent*>(actor)->mSerial;
161 }
162 
GetIPDLActor()163 PTextureParent* TextureHost::GetIPDLActor() { return mActor; }
164 
SetLastFwdTransactionId(uint64_t aTransactionId)165 void TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) {
166   MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
167   mFwdTransactionId = aTransactionId;
168 }
169 
Create(const SurfaceDescriptor & aDesc,const ReadLockDescriptor & aReadLock,ISurfaceAllocator * aDeallocator,LayersBackend aBackend,TextureFlags aFlags,wr::MaybeExternalImageId & aExternalImageId)170 already_AddRefed<TextureHost> TextureHost::Create(
171     const SurfaceDescriptor& aDesc, const ReadLockDescriptor& aReadLock,
172     ISurfaceAllocator* aDeallocator, LayersBackend aBackend,
173     TextureFlags aFlags, wr::MaybeExternalImageId& aExternalImageId) {
174   RefPtr<TextureHost> result;
175 
176   switch (aDesc.type()) {
177     case SurfaceDescriptor::TSurfaceDescriptorBuffer:
178     case SurfaceDescriptor::TSurfaceDescriptorDIB:
179     case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
180     case SurfaceDescriptor::TSurfaceDescriptorGPUVideo:
181       result = CreateBackendIndependentTextureHost(aDesc, aDeallocator,
182                                                    aBackend, aFlags);
183       break;
184 
185     case SurfaceDescriptor::TEGLImageDescriptor:
186     case SurfaceDescriptor::TSurfaceTextureDescriptor:
187     case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
188     case SurfaceDescriptor::TSurfaceDescriptorDMABuf:
189       result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
190       break;
191 
192     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
193       if (aBackend == LayersBackend::LAYERS_OPENGL ||
194           aBackend == LayersBackend::LAYERS_WR) {
195         result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
196         break;
197       } else {
198         result = CreateTextureHostBasic(aDesc, aDeallocator, aBackend, aFlags);
199         break;
200       }
201 
202 #ifdef MOZ_X11
203     case SurfaceDescriptor::TSurfaceDescriptorX11: {
204       if (!aDeallocator->IsSameProcess()) {
205         NS_ERROR(
206             "A client process is trying to peek at our address space using a "
207             "X11Texture!");
208         return nullptr;
209       }
210 
211       const SurfaceDescriptorX11& desc = aDesc.get_SurfaceDescriptorX11();
212       result = MakeAndAddRef<X11TextureHost>(aFlags, desc);
213       break;
214     }
215 #endif
216 
217 #ifdef XP_WIN
218     case SurfaceDescriptor::TSurfaceDescriptorD3D10:
219     case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
220       result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
221       break;
222 #endif
223     case SurfaceDescriptor::TSurfaceDescriptorRecorded: {
224       const SurfaceDescriptorRecorded& desc =
225           aDesc.get_SurfaceDescriptorRecorded();
226       UniquePtr<SurfaceDescriptor> realDesc =
227           aDeallocator->AsCompositorBridgeParentBase()
228               ->LookupSurfaceDescriptorForClientDrawTarget(desc.drawTarget());
229       if (!realDesc) {
230         NS_WARNING("Failed to get descriptor for recorded texture.");
231         return nullptr;
232       }
233 
234       result = TextureHost::Create(*realDesc, aReadLock, aDeallocator, aBackend,
235                                    aFlags, aExternalImageId);
236       return result.forget();
237     }
238     default:
239       MOZ_CRASH("GFX: Unsupported Surface type host");
240   }
241 
242   if (!result) {
243     gfxCriticalNote << "TextureHost creation failure type=" << aDesc.type();
244   }
245 
246   if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
247     MOZ_ASSERT(aExternalImageId.isSome());
248     result =
249         new WebRenderTextureHost(aDesc, aFlags, result, aExternalImageId.ref());
250   }
251 
252   if (result) {
253     result->DeserializeReadLock(aReadLock, aDeallocator);
254   }
255 
256   return result.forget();
257 }
258 
CreateBackendIndependentTextureHost(const SurfaceDescriptor & aDesc,ISurfaceAllocator * aDeallocator,LayersBackend aBackend,TextureFlags aFlags)259 already_AddRefed<TextureHost> CreateBackendIndependentTextureHost(
260     const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
261     LayersBackend aBackend, TextureFlags aFlags) {
262   RefPtr<TextureHost> result;
263   switch (aDesc.type()) {
264     case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
265       const SurfaceDescriptorBuffer& bufferDesc =
266           aDesc.get_SurfaceDescriptorBuffer();
267       const MemoryOrShmem& data = bufferDesc.data();
268       switch (data.type()) {
269         case MemoryOrShmem::TShmem: {
270           const ipc::Shmem& shmem = data.get_Shmem();
271           const BufferDescriptor& desc = bufferDesc.desc();
272           if (!shmem.IsReadable()) {
273             // We failed to map the shmem so we can't verify its size. This
274             // should not be a fatal error, so just create the texture with
275             // nothing backing it.
276             result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
277             break;
278           }
279 
280           size_t bufSize = shmem.Size<char>();
281           size_t reqSize = SIZE_MAX;
282           switch (desc.type()) {
283             case BufferDescriptor::TYCbCrDescriptor: {
284               const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor();
285               reqSize = ImageDataSerializer::ComputeYCbCrBufferSize(
286                   ycbcr.ySize(), ycbcr.yStride(), ycbcr.cbCrSize(),
287                   ycbcr.cbCrStride(), ycbcr.yOffset(), ycbcr.cbOffset(),
288                   ycbcr.crOffset());
289               break;
290             }
291             case BufferDescriptor::TRGBDescriptor: {
292               const RGBDescriptor& rgb = desc.get_RGBDescriptor();
293               reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(),
294                                                                   rgb.format());
295               break;
296             }
297             default:
298               gfxCriticalError()
299                   << "Bad buffer host descriptor " << (int)desc.type();
300               MOZ_CRASH("GFX: Bad descriptor");
301           }
302 
303           if (reqSize == 0 || bufSize < reqSize) {
304             NS_ERROR(
305                 "A client process gave a shmem too small to fit for its "
306                 "descriptor!");
307             return nullptr;
308           }
309 
310           result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
311           break;
312         }
313         case MemoryOrShmem::Tuintptr_t: {
314           if (!aDeallocator->IsSameProcess()) {
315             NS_ERROR(
316                 "A client process is trying to peek at our address space using "
317                 "a MemoryTexture!");
318             return nullptr;
319           }
320 
321           result = new MemoryTextureHost(
322               reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
323               bufferDesc.desc(), aFlags);
324           break;
325         }
326         default:
327           gfxCriticalError()
328               << "Failed texture host for backend " << (int)data.type();
329           MOZ_CRASH("GFX: No texture host for backend");
330       }
331       break;
332     }
333     case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
334       if (aDesc.get_SurfaceDescriptorGPUVideo().type() ==
335           SurfaceDescriptorGPUVideo::TSurfaceDescriptorPlugin) {
336         MOZ_ASSERT(aDeallocator && aDeallocator->UsesImageBridge());
337         auto ibpBase = static_cast<ImageBridgeParent*>(aDeallocator);
338         result =
339             ibpBase->LookupTextureHost(aDesc.get_SurfaceDescriptorGPUVideo());
340         if (!result) {
341           return nullptr;
342         }
343         MOZ_ASSERT(aFlags == result->GetFlags());
344         break;
345       }
346 
347       MOZ_ASSERT(aDesc.get_SurfaceDescriptorGPUVideo().type() ==
348                  SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder);
349       result = GPUVideoTextureHost::CreateFromDescriptor(
350           aFlags, aDesc.get_SurfaceDescriptorGPUVideo());
351       break;
352     }
353 #ifdef XP_WIN
354     case SurfaceDescriptor::TSurfaceDescriptorDIB: {
355       if (!aDeallocator->IsSameProcess()) {
356         NS_ERROR(
357             "A client process is trying to peek at our address space using a "
358             "DIBTexture!");
359         return nullptr;
360       }
361 
362       result = new DIBTextureHost(aFlags, aDesc);
363       break;
364     }
365     case SurfaceDescriptor::TSurfaceDescriptorFileMapping: {
366       result = new TextureHostFileMapping(aFlags, aDesc);
367       break;
368     }
369 #endif
370     default: {
371       NS_WARNING("No backend independent TextureHost for this descriptor type");
372     }
373   }
374   return result.forget();
375 }
376 
TextureHost(TextureFlags aFlags)377 TextureHost::TextureHost(TextureFlags aFlags)
378     : AtomicRefCountedWithFinalize("TextureHost"),
379       mActor(nullptr),
380       mFlags(aFlags),
381       mCompositableCount(0),
382       mFwdTransactionId(0),
383       mReadLocked(false) {}
384 
~TextureHost()385 TextureHost::~TextureHost() {
386   if (mReadLocked) {
387     // If we still have a ReadLock, unlock it. At this point we don't care about
388     // the texture client being written into on the other side since it should
389     // be destroyed by now. But we will hit assertions if we don't ReadUnlock
390     // before destroying the lock itself.
391     ReadUnlock();
392     MaybeNotifyUnlocked();
393   }
394 }
395 
Finalize()396 void TextureHost::Finalize() {
397   MaybeDestroyRenderTexture();
398 
399   if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) {
400     DeallocateSharedData();
401     DeallocateDeviceData();
402   }
403 }
404 
UnbindTextureSource()405 void TextureHost::UnbindTextureSource() {
406   if (mReadLocked) {
407     // This TextureHost is not used anymore. Since most compositor backends are
408     // working asynchronously under the hood a compositor could still be using
409     // this texture, so it is generally best to wait until the end of the next
410     // composition before calling ReadUnlock. We ask the compositor to take care
411     // of that for us.
412     if (mProvider) {
413       mProvider->UnlockAfterComposition(this);
414     } else {
415       // GetCompositor returned null which means no compositor can be using this
416       // texture. We can ReadUnlock right away.
417       ReadUnlock();
418       MaybeNotifyUnlocked();
419     }
420   }
421 }
422 
RecycleTexture(TextureFlags aFlags)423 void TextureHost::RecycleTexture(TextureFlags aFlags) {
424   MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
425   MOZ_ASSERT(aFlags & TextureFlags::RECYCLE);
426   mFlags = aFlags;
427 }
428 
NotifyNotUsed()429 void TextureHost::NotifyNotUsed() {
430   if (!mActor) {
431     return;
432   }
433 
434   // Do not need to call NotifyNotUsed() if TextureHost does not have
435   // TextureFlags::RECYCLE flag.
436   if (!(GetFlags() & TextureFlags::RECYCLE)) {
437     return;
438   }
439 
440   // The following cases do not need to defer NotifyNotUsed until next
441   // Composite.
442   // - TextureHost does not have Compositor.
443   // - Compositor is BasicCompositor.
444   // - TextureHost has intermediate buffer.
445   //   end of buffer usage.
446   if (!mProvider || HasIntermediateBuffer() ||
447       !mProvider->NotifyNotUsedAfterComposition(this)) {
448     static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
449     return;
450   }
451 }
452 
CallNotifyNotUsed()453 void TextureHost::CallNotifyNotUsed() {
454   if (!mActor) {
455     return;
456   }
457   static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
458 }
459 
MaybeDestroyRenderTexture()460 void TextureHost::MaybeDestroyRenderTexture() {
461   if (mExternalImageId.isNothing()) {
462     // RenderTextureHost was not created
463     return;
464   }
465   // When TextureHost created RenderTextureHost, delete it here.
466   TextureHost::DestroyRenderTexture(mExternalImageId.ref());
467 }
468 
DestroyRenderTexture(const wr::ExternalImageId & aExternalImageId)469 void TextureHost::DestroyRenderTexture(
470     const wr::ExternalImageId& aExternalImageId) {
471   wr::RenderThread::Get()->UnregisterExternalImage(
472       wr::AsUint64(aExternalImageId));
473 }
474 
EnsureRenderTexture(const wr::MaybeExternalImageId & aExternalImageId)475 void TextureHost::EnsureRenderTexture(
476     const wr::MaybeExternalImageId& aExternalImageId) {
477   if (aExternalImageId.isNothing()) {
478     // TextureHost is wrapped by GPUVideoTextureHost.
479     if (mExternalImageId.isSome()) {
480       // RenderTextureHost was already created.
481       return;
482     }
483     mExternalImageId =
484         Some(AsyncImagePipelineManager::GetNextExternalImageId());
485   } else {
486     // TextureHost is wrapped by WebRenderTextureHost.
487     MOZ_ASSERT(mExternalImageId.isNothing());
488     mExternalImageId = aExternalImageId;
489   }
490   CreateRenderTexture(mExternalImageId.ref());
491 }
492 
PrintInfo(std::stringstream & aStream,const char * aPrefix)493 void TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
494   aStream << aPrefix;
495   aStream << nsPrintfCString("%s (0x%p)", Name(), this).get();
496   // Note: the TextureHost needs to be locked before it is safe to call
497   //       GetSize() and GetFormat() on it.
498   if (Lock()) {
499     AppendToString(aStream, GetSize(), " [size=", "]");
500     AppendToString(aStream, GetFormat(), " [format=", "]");
501     Unlock();
502   }
503   AppendToString(aStream, mFlags, " [flags=", "]");
504 #ifdef MOZ_DUMP_PAINTING
505   if (StaticPrefs::layers_dump_texture()) {
506     nsAutoCString pfx(aPrefix);
507     pfx += "  ";
508 
509     aStream << "\n" << pfx.get() << "Surface: ";
510     RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
511     if (dSurf) {
512       aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
513     }
514   }
515 #endif
516 }
517 
Updated(const nsIntRegion * aRegion)518 void TextureHost::Updated(const nsIntRegion* aRegion) {
519   LayerScope::ContentChanged(this);
520   UpdatedInternal(aRegion);
521 }
522 
TextureSource()523 TextureSource::TextureSource() : mCompositableCount(0) {}
524 
525 TextureSource::~TextureSource() = default;
BufferTextureHost(const BufferDescriptor & aDesc,TextureFlags aFlags)526 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
527                                      TextureFlags aFlags)
528     : TextureHost(aFlags),
529       mUpdateSerial(1),
530       mLocked(false),
531       mNeedsFullUpdate(false) {
532   mDescriptor = aDesc;
533   switch (mDescriptor.type()) {
534     case BufferDescriptor::TYCbCrDescriptor: {
535       const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
536       mSize = ycbcr.ySize();
537       mFormat = gfx::SurfaceFormat::YUV;
538       mHasIntermediateBuffer = ycbcr.hasIntermediateBuffer();
539       break;
540     }
541     case BufferDescriptor::TRGBDescriptor: {
542       const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
543       mSize = rgb.size();
544       mFormat = rgb.format();
545       mHasIntermediateBuffer = rgb.hasIntermediateBuffer();
546       break;
547     }
548     default:
549       gfxCriticalError() << "Bad buffer host descriptor "
550                          << (int)mDescriptor.type();
551       MOZ_CRASH("GFX: Bad descriptor");
552   }
553   if (aFlags & TextureFlags::COMPONENT_ALPHA) {
554     // One texture of a component alpha texture pair will start out all white.
555     // This hack allows us to easily make sure that white will be uploaded.
556     // See bug 1138934
557     mNeedsFullUpdate = true;
558   }
559 }
560 
561 BufferTextureHost::~BufferTextureHost() = default;
562 
UpdatedInternal(const nsIntRegion * aRegion)563 void BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion) {
564   ++mUpdateSerial;
565   // If the last frame wasn't uploaded yet, and we -don't- have a partial
566   // update, we still need to update the full surface.
567   if (aRegion && !mNeedsFullUpdate) {
568     mMaybeUpdatedRegion.OrWith(*aRegion);
569   } else {
570     mNeedsFullUpdate = true;
571   }
572   if (GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) {
573     DebugOnly<bool> result =
574         MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr);
575     NS_WARNING_ASSERTION(result, "Failed to upload a texture");
576   }
577 }
578 
SetTextureSourceProvider(TextureSourceProvider * aProvider)579 void BufferTextureHost::SetTextureSourceProvider(
580     TextureSourceProvider* aProvider) {
581   if (mProvider == aProvider) {
582     return;
583   }
584   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
585     mFirstSource->SetOwner(nullptr);
586   }
587   if (mFirstSource) {
588     mFirstSource = nullptr;
589     mNeedsFullUpdate = true;
590   }
591   mProvider = aProvider;
592 }
593 
DeallocateDeviceData()594 void BufferTextureHost::DeallocateDeviceData() {
595   if (mFirstSource && mFirstSource->NumCompositableRefs() > 0) {
596     // WrappingTextureSourceYCbCrBasic wraps YUV format BufferTextureHost.
597     // When BufferTextureHost is destroyed, data of
598     // WrappingTextureSourceYCbCrBasic becomes invalid.
599     if (mFirstSource->AsWrappingTextureSourceYCbCrBasic() &&
600         mFirstSource->IsOwnedBy(this)) {
601       mFirstSource->SetOwner(nullptr);
602       mFirstSource->DeallocateDeviceData();
603     }
604     return;
605   }
606 
607   if (!mFirstSource || !mFirstSource->IsOwnedBy(this)) {
608     mFirstSource = nullptr;
609     return;
610   }
611 
612   mFirstSource->SetOwner(nullptr);
613 
614   RefPtr<TextureSource> it = mFirstSource;
615   while (it) {
616     it->DeallocateDeviceData();
617     it = it->GetNextSibling();
618   }
619 }
620 
Lock()621 bool BufferTextureHost::Lock() {
622   MOZ_ASSERT(!mLocked);
623   if (!UploadIfNeeded()) {
624     return false;
625   }
626   mLocked = !!mFirstSource;
627   return mLocked;
628 }
629 
Unlock()630 void BufferTextureHost::Unlock() {
631   MOZ_ASSERT(mLocked);
632   mLocked = false;
633 }
634 
CreateRenderTexture(const wr::ExternalImageId & aExternalImageId)635 void BufferTextureHost::CreateRenderTexture(
636     const wr::ExternalImageId& aExternalImageId) {
637   RefPtr<wr::RenderTextureHost> texture =
638       new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor());
639 
640   wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
641                                                  texture.forget());
642 }
643 
NumSubTextures()644 uint32_t BufferTextureHost::NumSubTextures() {
645   if (GetFormat() == gfx::SurfaceFormat::YUV) {
646     return 3;
647   }
648 
649   return 1;
650 }
651 
PushResourceUpdates(wr::TransactionBuilder & aResources,ResourceUpdateOp aOp,const Range<wr::ImageKey> & aImageKeys,const wr::ExternalImageId & aExtID)652 void BufferTextureHost::PushResourceUpdates(
653     wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
654     const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
655   auto method = aOp == TextureHost::ADD_IMAGE
656                     ? &wr::TransactionBuilder::AddExternalImage
657                     : &wr::TransactionBuilder::UpdateExternalImage;
658   auto imageType = wr::ExternalImageType::Buffer();
659 
660   if (GetFormat() != gfx::SurfaceFormat::YUV) {
661     MOZ_ASSERT(aImageKeys.length() == 1);
662 
663     wr::ImageDescriptor descriptor(
664         GetSize(),
665         ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
666         GetFormat());
667     (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
668   } else {
669     MOZ_ASSERT(aImageKeys.length() == 3);
670 
671     const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
672     wr::ImageDescriptor yDescriptor(
673         desc.ySize(), desc.yStride(),
674         SurfaceFormatForColorDepth(desc.colorDepth()));
675     wr::ImageDescriptor cbcrDescriptor(
676         desc.cbCrSize(), desc.cbCrStride(),
677         SurfaceFormatForColorDepth(desc.colorDepth()));
678     (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0);
679     (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1);
680     (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2);
681   }
682 }
683 
PushDisplayItems(wr::DisplayListBuilder & aBuilder,const wr::LayoutRect & aBounds,const wr::LayoutRect & aClip,wr::ImageRendering aFilter,const Range<wr::ImageKey> & aImageKeys,const bool aPreferCompositorSurface)684 void BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
685                                          const wr::LayoutRect& aBounds,
686                                          const wr::LayoutRect& aClip,
687                                          wr::ImageRendering aFilter,
688                                          const Range<wr::ImageKey>& aImageKeys,
689                                          const bool aPreferCompositorSurface) {
690   if (GetFormat() != gfx::SurfaceFormat::YUV) {
691     MOZ_ASSERT(aImageKeys.length() == 1);
692     aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0],
693                        !(mFlags & TextureFlags::NON_PREMULTIPLIED),
694                        wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
695                        aPreferCompositorSurface);
696   } else {
697     MOZ_ASSERT(aImageKeys.length() == 3);
698     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
699     aBuilder.PushYCbCrPlanarImage(aBounds, aClip, true, aImageKeys[0],
700                                   aImageKeys[1], aImageKeys[2],
701                                   wr::ToWrColorDepth(desc.colorDepth()),
702                                   wr::ToWrYuvColorSpace(desc.yUVColorSpace()),
703                                   wr::ToWrColorRange(desc.colorRange()),
704                                   aFilter, aPreferCompositorSurface);
705   }
706 }
707 
DeserializeReadLock(const ReadLockDescriptor & aDesc,ISurfaceAllocator * aAllocator)708 void TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc,
709                                       ISurfaceAllocator* aAllocator) {
710   if (mReadLock) {
711     return;
712   }
713 
714   mReadLock = TextureReadLock::Deserialize(aDesc, aAllocator);
715 }
716 
SetReadLocked()717 void TextureHost::SetReadLocked() {
718   if (!mReadLock) {
719     return;
720   }
721   // If mReadLocked is true it means we haven't read unlocked yet and the
722   // content side should not have been able to write into this texture and read
723   // lock again!
724   MOZ_ASSERT(!mReadLocked);
725   mReadLocked = true;
726   if (mProvider) {
727     mProvider->MaybeUnlockBeforeNextComposition(this);
728   }
729 }
730 
ReadUnlock()731 void TextureHost::ReadUnlock() {
732   if (mReadLock && mReadLocked) {
733     mReadLock->ReadUnlock();
734     mReadLocked = false;
735   }
736 }
737 
NeedsYFlip() const738 bool TextureHost::NeedsYFlip() const {
739   return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT);
740 }
741 
EnsureWrappingTextureSource()742 bool BufferTextureHost::EnsureWrappingTextureSource() {
743   MOZ_ASSERT(!mHasIntermediateBuffer);
744 
745   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
746     return true;
747   }
748   // We don't own it, apparently.
749   if (mFirstSource) {
750     mNeedsFullUpdate = true;
751     mFirstSource = nullptr;
752   }
753 
754   if (!mProvider) {
755     return false;
756   }
757 
758   if (mFormat == gfx::SurfaceFormat::YUV) {
759     mFirstSource = mProvider->CreateDataTextureSourceAroundYCbCr(this);
760   } else {
761     RefPtr<gfx::DataSourceSurface> surf =
762         gfx::Factory::CreateWrappingDataSourceSurface(
763             GetBuffer(),
764             ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize,
765             mFormat);
766     if (!surf) {
767       return false;
768     }
769     mFirstSource = mProvider->CreateDataTextureSourceAround(surf);
770   }
771 
772   if (!mFirstSource) {
773     // BasicCompositor::CreateDataTextureSourceAround never returns null
774     // and we don't expect to take this branch if we are using another backend.
775     // Returning false is fine but if we get into this situation it probably
776     // means something fishy is going on, like a texture being used with
777     // several compositor backends.
778     NS_WARNING("Failed to use a BufferTextureHost without intermediate buffer");
779     return false;
780   }
781 
782   mFirstSource->SetUpdateSerial(mUpdateSerial);
783   mFirstSource->SetOwner(this);
784 
785   return true;
786 }
787 
IsCompatibleTextureSource(TextureSource * aTexture,const BufferDescriptor & aDescriptor,TextureSourceProvider * aProvider)788 static bool IsCompatibleTextureSource(TextureSource* aTexture,
789                                       const BufferDescriptor& aDescriptor,
790                                       TextureSourceProvider* aProvider) {
791   if (!aProvider) {
792     return false;
793   }
794 
795   switch (aDescriptor.type()) {
796     case BufferDescriptor::TYCbCrDescriptor: {
797       const YCbCrDescriptor& ycbcr = aDescriptor.get_YCbCrDescriptor();
798 
799       if (!aProvider->SupportsEffect(EffectTypes::YCBCR)) {
800         return aTexture->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 &&
801                aTexture->GetSize() == ycbcr.ySize();
802       }
803 
804       if (aTexture->GetFormat() != gfx::SurfaceFormat::A8 ||
805           aTexture->GetSize() != ycbcr.ySize()) {
806         return false;
807       }
808 
809       auto cbTexture = aTexture->GetSubSource(1);
810       if (!cbTexture || cbTexture->GetFormat() != gfx::SurfaceFormat::A8 ||
811           cbTexture->GetSize() != ycbcr.cbCrSize()) {
812         return false;
813       }
814 
815       auto crTexture = aTexture->GetSubSource(2);
816       if (!crTexture || crTexture->GetFormat() != gfx::SurfaceFormat::A8 ||
817           crTexture->GetSize() != ycbcr.cbCrSize()) {
818         return false;
819       }
820 
821       return true;
822     }
823     case BufferDescriptor::TRGBDescriptor: {
824       const RGBDescriptor& rgb = aDescriptor.get_RGBDescriptor();
825       return aTexture->GetFormat() == rgb.format() &&
826              aTexture->GetSize() == rgb.size();
827     }
828     default: {
829       return false;
830     }
831   }
832 }
833 
PrepareTextureSource(CompositableTextureSourceRef & aTexture)834 void BufferTextureHost::PrepareTextureSource(
835     CompositableTextureSourceRef& aTexture) {
836   // Reuse WrappingTextureSourceYCbCrBasic to reduce memory consumption.
837   if (mFormat == gfx::SurfaceFormat::YUV && !mHasIntermediateBuffer &&
838       aTexture.get() && aTexture->AsWrappingTextureSourceYCbCrBasic() &&
839       aTexture->NumCompositableRefs() <= 1 &&
840       aTexture->GetSize() == GetSize()) {
841     aTexture->AsSourceBasic()->SetBufferTextureHost(this);
842     aTexture->AsDataTextureSource()->SetOwner(this);
843     mFirstSource = aTexture->AsDataTextureSource();
844     mNeedsFullUpdate = true;
845   }
846 
847   if (!mHasIntermediateBuffer) {
848     EnsureWrappingTextureSource();
849   }
850 
851   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
852     // We are already attached to a TextureSource, nothing to do except tell
853     // the compositable to use it.
854     aTexture = mFirstSource.get();
855     return;
856   }
857 
858   // We don't own it, apparently.
859   if (mFirstSource) {
860     mNeedsFullUpdate = true;
861     mFirstSource = nullptr;
862   }
863 
864   DataTextureSource* texture =
865       aTexture.get() ? aTexture->AsDataTextureSource() : nullptr;
866 
867   bool compatibleFormats =
868       texture && IsCompatibleTextureSource(texture, mDescriptor, mProvider);
869 
870   bool shouldCreateTexture = !compatibleFormats ||
871                              texture->NumCompositableRefs() > 1 ||
872                              texture->HasOwner();
873 
874   if (!shouldCreateTexture) {
875     mFirstSource = texture;
876     mFirstSource->SetOwner(this);
877     mNeedsFullUpdate = true;
878 
879     // It's possible that texture belonged to a different compositor,
880     // so make sure we update it (and all of its siblings) to the
881     // current one.
882     RefPtr<TextureSource> it = mFirstSource;
883     while (it) {
884       it->SetTextureSourceProvider(mProvider);
885       it = it->GetNextSibling();
886     }
887   }
888 }
889 
BindTextureSource(CompositableTextureSourceRef & aTexture)890 bool BufferTextureHost::BindTextureSource(
891     CompositableTextureSourceRef& aTexture) {
892   MOZ_ASSERT(mLocked);
893   MOZ_ASSERT(mFirstSource);
894   aTexture = mFirstSource;
895   return !!aTexture;
896 }
897 
AcquireTextureSource(CompositableTextureSourceRef & aTexture)898 bool BufferTextureHost::AcquireTextureSource(
899     CompositableTextureSourceRef& aTexture) {
900   if (!UploadIfNeeded()) {
901     return false;
902   }
903   aTexture = mFirstSource;
904   return !!mFirstSource;
905 }
906 
ReadUnlock()907 void BufferTextureHost::ReadUnlock() {
908   if (mFirstSource) {
909     mFirstSource->Sync(true);
910   }
911 
912   TextureHost::ReadUnlock();
913 }
914 
MaybeNotifyUnlocked()915 void BufferTextureHost::MaybeNotifyUnlocked() {
916 #ifdef XP_DARWIN
917   auto actor = GetIPDLActor();
918   if (actor) {
919     AutoTArray<uint64_t, 1> serials;
920     serials.AppendElement(TextureHost::GetTextureSerial(actor));
921     TextureSync::SetTexturesUnlocked(actor->OtherPid(), serials);
922   }
923 #endif
924 }
925 
UnbindTextureSource()926 void BufferTextureHost::UnbindTextureSource() {
927   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
928     mFirstSource->Unbind();
929   }
930 
931   // This texture is not used by any layer anymore.
932   // If the texture doesn't have an intermediate buffer, it means we are
933   // compositing synchronously on the CPU, so we don't need to wait until
934   // the end of the next composition to ReadUnlock (which other textures do
935   // by default).
936   // If the texture has an intermediate buffer we don't care either because
937   // texture uploads are also performed synchronously for BufferTextureHost.
938   ReadUnlock();
939   MaybeNotifyUnlocked();
940 }
941 
GetFormat() const942 gfx::SurfaceFormat BufferTextureHost::GetFormat() const {
943   // mFormat is the format of the data that we share with the content process.
944   // GetFormat, on the other hand, expects the format that we present to the
945   // Compositor (it is used to choose the effect type).
946   // if the compositor does not support YCbCr effects, we give it a RGBX texture
947   // instead (see BufferTextureHost::Upload)
948   if (mFormat == gfx::SurfaceFormat::YUV && mProvider &&
949       !mProvider->SupportsEffect(EffectTypes::YCBCR)) {
950     return gfx::SurfaceFormat::R8G8B8X8;
951   }
952   return mFormat;
953 }
954 
GetYUVColorSpace() const955 gfx::YUVColorSpace BufferTextureHost::GetYUVColorSpace() const {
956   if (mFormat == gfx::SurfaceFormat::YUV) {
957     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
958     return desc.yUVColorSpace();
959   }
960   return gfx::YUVColorSpace::UNKNOWN;
961 }
962 
GetColorDepth() const963 gfx::ColorDepth BufferTextureHost::GetColorDepth() const {
964   if (mFormat == gfx::SurfaceFormat::YUV) {
965     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
966     return desc.colorDepth();
967   }
968   return gfx::ColorDepth::COLOR_8;
969 }
970 
GetColorRange() const971 gfx::ColorRange BufferTextureHost::GetColorRange() const {
972   if (mFormat == gfx::SurfaceFormat::YUV) {
973     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
974     return desc.colorRange();
975   }
976   return TextureHost::GetColorRange();
977 }
978 
UploadIfNeeded()979 bool BufferTextureHost::UploadIfNeeded() {
980   return MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr);
981 }
982 
MaybeUpload(nsIntRegion * aRegion)983 bool BufferTextureHost::MaybeUpload(nsIntRegion* aRegion) {
984   auto serial = mFirstSource ? mFirstSource->GetUpdateSerial() : 0;
985 
986   if (serial == mUpdateSerial) {
987     return true;
988   }
989 
990   if (serial == 0) {
991     // 0 means the source has no valid content
992     aRegion = nullptr;
993   }
994 
995   if (!Upload(aRegion)) {
996     return false;
997   }
998 
999   if (mHasIntermediateBuffer) {
1000     // We just did the texture upload, the content side can now freely write
1001     // into the shared buffer.
1002     ReadUnlock();
1003     MaybeNotifyUnlocked();
1004   }
1005 
1006   // We no longer have an invalid region.
1007   mNeedsFullUpdate = false;
1008   mMaybeUpdatedRegion.SetEmpty();
1009 
1010   // If upload returns true we know mFirstSource is not null
1011   mFirstSource->SetUpdateSerial(mUpdateSerial);
1012   return true;
1013 }
1014 
Upload(nsIntRegion * aRegion)1015 bool BufferTextureHost::Upload(nsIntRegion* aRegion) {
1016   uint8_t* buf = GetBuffer();
1017   if (!buf) {
1018     // We don't have a buffer; a possible cause is that the IPDL actor
1019     // is already dead. This inevitably happens as IPDL actors can die
1020     // at any time, so we want to silently return in this case.
1021     // another possible cause is that IPDL failed to map the shmem when
1022     // deserializing it.
1023     return false;
1024   }
1025   if (!mProvider) {
1026     // This can happen if we send textures to a compositable that isn't yet
1027     // attached to a layer.
1028     return false;
1029   }
1030   if (!mHasIntermediateBuffer && EnsureWrappingTextureSource()) {
1031     if (!mFirstSource || !mFirstSource->IsDirectMap()) {
1032       return true;
1033     }
1034   }
1035 
1036   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
1037     NS_WARNING("BufferTextureHost: unsupported format!");
1038     return false;
1039   } else if (mFormat == gfx::SurfaceFormat::YUV) {
1040     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
1041 
1042     if (!mProvider->SupportsEffect(EffectTypes::YCBCR)) {
1043       RefPtr<gfx::DataSourceSurface> surf =
1044           ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
1045               buf, mDescriptor.get_YCbCrDescriptor());
1046       if (NS_WARN_IF(!surf)) {
1047         return false;
1048       }
1049       if (!mFirstSource) {
1050         mFirstSource = mProvider->CreateDataTextureSource(
1051             mFlags | TextureFlags::RGB_FROM_YCBCR);
1052         mFirstSource->SetOwner(this);
1053       }
1054       return mFirstSource->Update(surf, aRegion);
1055     }
1056 
1057     RefPtr<DataTextureSource> srcY;
1058     RefPtr<DataTextureSource> srcU;
1059     RefPtr<DataTextureSource> srcV;
1060     if (!mFirstSource) {
1061       // We don't support BigImages for YCbCr compositing.
1062       srcY = mProvider->CreateDataTextureSource(
1063           mFlags | TextureFlags::DISALLOW_BIGIMAGE);
1064       srcU = mProvider->CreateDataTextureSource(
1065           mFlags | TextureFlags::DISALLOW_BIGIMAGE);
1066       srcV = mProvider->CreateDataTextureSource(
1067           mFlags | TextureFlags::DISALLOW_BIGIMAGE);
1068       mFirstSource = srcY;
1069       mFirstSource->SetOwner(this);
1070       srcY->SetNextSibling(srcU);
1071       srcU->SetNextSibling(srcV);
1072     } else {
1073       // mFormat never changes so if this was created as a YCbCr host and
1074       // already contains a source it should already have 3 sources.
1075       // BufferTextureHost only uses DataTextureSources so it is safe to assume
1076       // all 3 sources are DataTextureSource.
1077       MOZ_ASSERT(mFirstSource->GetNextSibling());
1078       MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());
1079       srcY = mFirstSource;
1080       srcU = mFirstSource->GetNextSibling()->AsDataTextureSource();
1081       srcV = mFirstSource->GetNextSibling()
1082                  ->GetNextSibling()
1083                  ->AsDataTextureSource();
1084     }
1085 
1086     RefPtr<gfx::DataSourceSurface> tempY =
1087         gfx::Factory::CreateWrappingDataSourceSurface(
1088             ImageDataSerializer::GetYChannel(buf, desc), desc.yStride(),
1089             desc.ySize(), SurfaceFormatForColorDepth(desc.colorDepth()));
1090     RefPtr<gfx::DataSourceSurface> tempCb =
1091         gfx::Factory::CreateWrappingDataSourceSurface(
1092             ImageDataSerializer::GetCbChannel(buf, desc), desc.cbCrStride(),
1093             desc.cbCrSize(), SurfaceFormatForColorDepth(desc.colorDepth()));
1094     RefPtr<gfx::DataSourceSurface> tempCr =
1095         gfx::Factory::CreateWrappingDataSourceSurface(
1096             ImageDataSerializer::GetCrChannel(buf, desc), desc.cbCrStride(),
1097             desc.cbCrSize(), SurfaceFormatForColorDepth(desc.colorDepth()));
1098     // We don't support partial updates for Y U V textures
1099     NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures");
1100     if (!tempY || !tempCb || !tempCr || !srcY->Update(tempY) ||
1101         !srcU->Update(tempCb) || !srcV->Update(tempCr)) {
1102       NS_WARNING("failed to update the DataTextureSource");
1103       return false;
1104     }
1105   } else {
1106     // non-YCbCr case
1107     nsIntRegion* regionToUpdate = aRegion;
1108     if (!mFirstSource) {
1109       mFirstSource = mProvider->CreateDataTextureSource(mFlags);
1110       mFirstSource->SetOwner(this);
1111       if (mFlags & TextureFlags::COMPONENT_ALPHA) {
1112         // Update the full region the first time for component alpha textures.
1113         regionToUpdate = nullptr;
1114       }
1115     }
1116 
1117     RefPtr<gfx::DataSourceSurface> surf =
1118         gfx::Factory::CreateWrappingDataSourceSurface(
1119             GetBuffer(),
1120             ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize,
1121             mFormat);
1122     if (!surf) {
1123       return false;
1124     }
1125 
1126     if (!mFirstSource->Update(surf.get(), regionToUpdate)) {
1127       NS_WARNING("failed to update the DataTextureSource");
1128       return false;
1129     }
1130   }
1131   MOZ_ASSERT(mFirstSource);
1132   return true;
1133 }
1134 
GetAsSurface()1135 already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface() {
1136   RefPtr<gfx::DataSourceSurface> result;
1137   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
1138     NS_WARNING("BufferTextureHost: unsupported format!");
1139     return nullptr;
1140   } else if (mFormat == gfx::SurfaceFormat::YUV) {
1141     result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
1142         GetBuffer(), mDescriptor.get_YCbCrDescriptor());
1143     if (NS_WARN_IF(!result)) {
1144       return nullptr;
1145     }
1146   } else {
1147     result = gfx::Factory::CreateWrappingDataSourceSurface(
1148         GetBuffer(),
1149         ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
1150         mSize, mFormat);
1151   }
1152   return result.forget();
1153 }
1154 
ShmemTextureHost(const ipc::Shmem & aShmem,const BufferDescriptor & aDesc,ISurfaceAllocator * aDeallocator,TextureFlags aFlags)1155 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
1156                                    const BufferDescriptor& aDesc,
1157                                    ISurfaceAllocator* aDeallocator,
1158                                    TextureFlags aFlags)
1159     : BufferTextureHost(aDesc, aFlags), mDeallocator(aDeallocator) {
1160   if (aShmem.IsReadable()) {
1161     mShmem = MakeUnique<ipc::Shmem>(aShmem);
1162   } else {
1163     // This can happen if we failed to map the shmem on this process, perhaps
1164     // because it was big and we didn't have enough contiguous address space
1165     // available, even though we did on the child process.
1166     // As a result this texture will be in an invalid state and Lock will
1167     // always fail.
1168 
1169     gfxCriticalNote << "Failed to create a valid ShmemTextureHost";
1170   }
1171 
1172   MOZ_COUNT_CTOR(ShmemTextureHost);
1173 }
1174 
~ShmemTextureHost()1175 ShmemTextureHost::~ShmemTextureHost() {
1176   MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
1177              "Leaking our buffer");
1178   DeallocateDeviceData();
1179   MOZ_COUNT_DTOR(ShmemTextureHost);
1180 }
1181 
DeallocateSharedData()1182 void ShmemTextureHost::DeallocateSharedData() {
1183   if (mShmem) {
1184     MOZ_ASSERT(mDeallocator,
1185                "Shared memory would leak without a ISurfaceAllocator");
1186     mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem);
1187     mShmem = nullptr;
1188   }
1189 }
1190 
ForgetSharedData()1191 void ShmemTextureHost::ForgetSharedData() {
1192   if (mShmem) {
1193     mShmem = nullptr;
1194   }
1195 }
1196 
OnShutdown()1197 void ShmemTextureHost::OnShutdown() { mShmem = nullptr; }
1198 
GetBuffer()1199 uint8_t* ShmemTextureHost::GetBuffer() {
1200   return mShmem ? mShmem->get<uint8_t>() : nullptr;
1201 }
1202 
GetBufferSize()1203 size_t ShmemTextureHost::GetBufferSize() {
1204   return mShmem ? mShmem->Size<uint8_t>() : 0;
1205 }
1206 
MemoryTextureHost(uint8_t * aBuffer,const BufferDescriptor & aDesc,TextureFlags aFlags)1207 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
1208                                      const BufferDescriptor& aDesc,
1209                                      TextureFlags aFlags)
1210     : BufferTextureHost(aDesc, aFlags), mBuffer(aBuffer) {
1211   MOZ_COUNT_CTOR(MemoryTextureHost);
1212 }
1213 
~MemoryTextureHost()1214 MemoryTextureHost::~MemoryTextureHost() {
1215   MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
1216              "Leaking our buffer");
1217   DeallocateDeviceData();
1218   MOZ_COUNT_DTOR(MemoryTextureHost);
1219 }
1220 
DeallocateSharedData()1221 void MemoryTextureHost::DeallocateSharedData() {
1222   if (mBuffer) {
1223     GfxMemoryImageReporter::WillFree(mBuffer);
1224   }
1225   delete[] mBuffer;
1226   mBuffer = nullptr;
1227 }
1228 
ForgetSharedData()1229 void MemoryTextureHost::ForgetSharedData() { mBuffer = nullptr; }
1230 
GetBuffer()1231 uint8_t* MemoryTextureHost::GetBuffer() { return mBuffer; }
1232 
GetBufferSize()1233 size_t MemoryTextureHost::GetBufferSize() {
1234   // MemoryTextureHost just trusts that the buffer size is large enough to read
1235   // anything we need to. That's because MemoryTextureHost has to trust the
1236   // buffer pointer anyway, so the security model here is just that
1237   // MemoryTexture's are restricted to same-process clients.
1238   return std::numeric_limits<size_t>::max();
1239 }
1240 
TextureParent(HostIPCAllocator * aSurfaceAllocator,uint64_t aSerial,const wr::MaybeExternalImageId & aExternalImageId)1241 TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator,
1242                              uint64_t aSerial,
1243                              const wr::MaybeExternalImageId& aExternalImageId)
1244     : mSurfaceAllocator(aSurfaceAllocator),
1245       mSerial(aSerial),
1246       mExternalImageId(aExternalImageId) {
1247   MOZ_COUNT_CTOR(TextureParent);
1248 }
1249 
~TextureParent()1250 TextureParent::~TextureParent() { MOZ_COUNT_DTOR(TextureParent); }
1251 
NotifyNotUsed(uint64_t aTransactionId)1252 void TextureParent::NotifyNotUsed(uint64_t aTransactionId) {
1253   if (!mTextureHost) {
1254     return;
1255   }
1256   mSurfaceAllocator->NotifyNotUsed(this, aTransactionId);
1257 }
1258 
Init(const SurfaceDescriptor & aSharedData,const ReadLockDescriptor & aReadLock,const LayersBackend & aBackend,const TextureFlags & aFlags)1259 bool TextureParent::Init(const SurfaceDescriptor& aSharedData,
1260                          const ReadLockDescriptor& aReadLock,
1261                          const LayersBackend& aBackend,
1262                          const TextureFlags& aFlags) {
1263   mTextureHost = TextureHost::Create(aSharedData, aReadLock, mSurfaceAllocator,
1264                                      aBackend, aFlags, mExternalImageId);
1265   if (mTextureHost) {
1266     mTextureHost->mActor = this;
1267   }
1268 
1269   return !!mTextureHost;
1270 }
1271 
Destroy()1272 void TextureParent::Destroy() {
1273   if (!mTextureHost) {
1274     return;
1275   }
1276 
1277   if (mTextureHost->mReadLocked) {
1278     // ReadUnlock here to make sure the ReadLock's shmem does not outlive the
1279     // protocol that created it.
1280     mTextureHost->ReadUnlock();
1281     mTextureHost->MaybeNotifyUnlocked();
1282   }
1283 
1284   if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
1285     mTextureHost->ForgetSharedData();
1286   }
1287 
1288   mTextureHost->mActor = nullptr;
1289   mTextureHost = nullptr;
1290 }
1291 
ReceivedDestroy(PTextureParent * aActor)1292 void TextureHost::ReceivedDestroy(PTextureParent* aActor) {
1293   static_cast<TextureParent*>(aActor)->RecvDestroy();
1294 }
1295 
RecvRecycleTexture(const TextureFlags & aTextureFlags)1296 mozilla::ipc::IPCResult TextureParent::RecvRecycleTexture(
1297     const TextureFlags& aTextureFlags) {
1298   if (!mTextureHost) {
1299     return IPC_OK();
1300   }
1301   mTextureHost->RecycleTexture(aTextureFlags);
1302   return IPC_OK();
1303 }
1304 
1305 ////////////////////////////////////////////////////////////////////////////////
1306 
1307 }  // namespace layers
1308 }  // namespace mozilla
1309