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 #ifndef MOZILLA_GFX_TEXTURECLIENT_H
8 #define MOZILLA_GFX_TEXTURECLIENT_H
9 
10 #include <stddef.h>  // for size_t
11 #include <stdint.h>  // for uint32_t, uint8_t, uint64_t
12 
13 #include "GLTextureImage.h"  // for TextureImage
14 #include "GfxTexturesReporter.h"
15 #include "ImageTypes.h"          // for StereoMode
16 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
17 #include "mozilla/Atomics.h"
18 #include "mozilla/Attributes.h"  // for override
19 #include "mozilla/DebugOnly.h"
20 #include "mozilla/RefPtr.h"  // for RefPtr, RefCounted
21 #include "mozilla/gfx/2D.h"  // for DrawTarget
22 #include "mozilla/gfx/CriticalSection.h"
23 #include "mozilla/gfx/Point.h"  // for IntSize
24 #include "mozilla/gfx/Types.h"  // for SurfaceFormat
25 #include "mozilla/ipc/FileDescriptor.h"
26 #include "mozilla/ipc/Shmem.h"  // for Shmem
27 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
28 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
29 #include "mozilla/layers/ISurfaceAllocator.h"
30 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
31 #include "mozilla/layers/LayersTypes.h"
32 #include "mozilla/layers/SyncObject.h"
33 #include "mozilla/mozalloc.h"  // for operator delete
34 #include "mozilla/webrender/WebRenderTypes.h"
35 #include "nsCOMPtr.h"         // for already_AddRefed
36 #include "nsISupportsImpl.h"  // for TextureImage::AddRef, etc
37 #include "nsThreadUtils.h"
38 #include "pratom.h"
39 
40 class gfxImageSurface;
41 struct ID3D11Device;
42 
43 namespace mozilla {
44 
45 // When defined, we track which pool the tile came from and test for
46 // any inconsistencies.  This can be defined in release build as well.
47 #ifdef DEBUG
48 #  define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1
49 #endif
50 
51 namespace layers {
52 
53 class AndroidHardwareBufferTextureData;
54 class BufferTextureData;
55 class CompositableForwarder;
56 class KnowsCompositor;
57 class LayersIPCChannel;
58 class CompositableClient;
59 struct PlanarYCbCrData;
60 class Image;
61 class PTextureChild;
62 class TextureChild;
63 class TextureData;
64 class GPUVideoTextureData;
65 struct RawTextureBuffer;
66 class RawYCbCrTextureBuffer;
67 class TextureClient;
68 class ITextureClientRecycleAllocator;
69 #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
70 class TextureClientPool;
71 #endif
72 class TextureForwarder;
73 class KeepAlive;
74 
75 /**
76  * TextureClient is the abstraction that allows us to share data between the
77  * content and the compositor side.
78  */
79 
80 enum TextureAllocationFlags {
81   ALLOC_DEFAULT = 0,
82   ALLOC_CLEAR_BUFFER =
83       1 << 1,  // Clear the buffer to whatever is best for the draw target
84   ALLOC_CLEAR_BUFFER_WHITE = 1 << 2,  // explicit all white
85   ALLOC_CLEAR_BUFFER_BLACK = 1 << 3,  // explicit all black
86   ALLOC_DISALLOW_BUFFERTEXTURECLIENT = 1 << 4,
87 
88   // Allocate the texture for out-of-band content updates. This is mostly for
89   // TextureClientD3D11, which may otherwise choose D3D10 or non-KeyedMutex
90   // surfaces when used on the main thread.
91   ALLOC_FOR_OUT_OF_BAND_CONTENT = 1 << 5,
92 
93   // Disable any cross-device synchronization. This is also for
94   // TextureClientD3D11, and creates a texture without KeyedMutex.
95   ALLOC_MANUAL_SYNCHRONIZATION = 1 << 6,
96 
97   // The texture is going to be updated using UpdateFromSurface and needs to
98   // support that call.
99   ALLOC_UPDATE_FROM_SURFACE = 1 << 7,
100 
101   // In practice, this means we support the APPLE_client_storage extension,
102   // meaning the buffer will not be internally copied by the graphics driver.
103   ALLOC_ALLOW_DIRECT_MAPPING = 1 << 8,
104 };
105 
106 /**
107  * This class may be used to asynchronously receive an update when the content
108  * drawn to this texture client is available for reading in CPU memory. This
109  * can only be used on texture clients that support draw target creation.
110  */
111 class TextureReadbackSink {
112   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadbackSink)
113  public:
114   /**
115    * Callback function to implement in order to receive a DataSourceSurface
116    * containing the data read back from the texture client. This will always
117    * be called on the main thread, and this may not hold on to the
118    * DataSourceSurface beyond the execution of this function.
119    */
120   virtual void ProcessReadback(gfx::DataSourceSurface* aSourceSurface) = 0;
121 
122  protected:
123   virtual ~TextureReadbackSink() = default;
124 };
125 
126 enum class BackendSelector { Content, Canvas };
127 
128 /// Temporary object providing direct access to a Texture's memory.
129 ///
130 /// see TextureClient::CanExposeMappedData() and
131 /// TextureClient::BorrowMappedData().
132 struct MappedTextureData {
133   uint8_t* data;
134   gfx::IntSize size;
135   int32_t stride;
136   gfx::SurfaceFormat format;
137 };
138 
139 struct MappedYCbCrChannelData {
140   uint8_t* data;
141   gfx::IntSize size;
142   int32_t stride;
143   int32_t skip;
144   uint32_t bytesPerPixel;
145 
146   bool CopyInto(MappedYCbCrChannelData& aDst);
147 };
148 
149 struct MappedYCbCrTextureData {
150   MappedYCbCrChannelData y;
151   MappedYCbCrChannelData cb;
152   MappedYCbCrChannelData cr;
153   // Sad but because of how SharedPlanarYCbCrData is used we have to expose this
154   // for now.
155   uint8_t* metadata;
156   StereoMode stereoMode;
157 
CopyIntoMappedYCbCrTextureData158   bool CopyInto(MappedYCbCrTextureData& aDst) {
159     return y.CopyInto(aDst.y) && cb.CopyInto(aDst.cb) && cr.CopyInto(aDst.cr);
160   }
161 };
162 
163 class ReadLockDescriptor;
164 class NonBlockingTextureReadLock;
165 
166 // A class to help implement copy-on-write semantics for shared textures.
167 //
168 // A TextureClient/Host pair can opt into using a ReadLock by calling
169 // TextureClient::EnableReadLock. This will equip the TextureClient with a
170 // ReadLock object that will be automatically ReadLock()'ed by the texture
171 // itself when it is written into (see TextureClient::Unlock). A
172 // TextureReadLock's counter starts at 1 and is expected to be equal to 1 when
173 // the lock is destroyed. See ShmemTextureReadLock for explanations about why we
174 // use 1 instead of 0 as the initial state. TextureReadLock is mostly internally
175 // managed by the TextureClient/Host pair, and the compositable only has to
176 // forward it during updates. If an update message contains a null_t lock, it
177 // means that the texture was not written into on the content side, and there is
178 // no synchronization required on the compositor side (or it means that the
179 // texture pair did not opt into using ReadLocks). On the compositor side, the
180 // TextureHost can receive a ReadLock during a transaction, and will both
181 // ReadUnlock() it and drop it as soon as the shared data is available again for
182 // writing (the texture upload is done, or the compositor not reading the
183 // texture anymore). The lock is dropped to make sure it is ReadUnlock()'ed only
184 // once.
185 class TextureReadLock {
186  protected:
187   virtual ~TextureReadLock() = default;
188 
189  public:
190   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureReadLock)
191 
192   virtual bool ReadLock() = 0;
TryReadLock(TimeDuration aTimeout)193   virtual bool TryReadLock(TimeDuration aTimeout) { return ReadLock(); }
194   virtual int32_t ReadUnlock() = 0;
195   virtual bool IsValid() const = 0;
196 
197   static already_AddRefed<TextureReadLock> Deserialize(
198       const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator);
199 
200   virtual bool Serialize(ReadLockDescriptor& aOutput,
201                          base::ProcessId aOther) = 0;
202 
203   enum LockType {
204     TYPE_NONBLOCKING_MEMORY,
205     TYPE_NONBLOCKING_SHMEM,
206     TYPE_CROSS_PROCESS_SEMAPHORE
207   };
208   virtual LockType GetType() = 0;
209 
AsNonBlockingLock()210   virtual NonBlockingTextureReadLock* AsNonBlockingLock() { return nullptr; }
211 
212  protected:
213   NS_DECL_OWNINGTHREAD
214 };
215 
216 class NonBlockingTextureReadLock : public TextureReadLock {
217  public:
218   virtual int32_t GetReadCount() = 0;
219 
220   static already_AddRefed<TextureReadLock> Create(LayersIPCChannel* aAllocator);
221 
AsNonBlockingLock()222   NonBlockingTextureReadLock* AsNonBlockingLock() override { return this; }
223 };
224 
225 #ifdef XP_WIN
226 class D3D11TextureData;
227 class DXGIYCbCrTextureData;
228 #endif
229 
230 class TextureData {
231  public:
232   struct Info {
233     gfx::IntSize size;
234     gfx::SurfaceFormat format;
235     bool hasIntermediateBuffer;
236     bool hasSynchronization;
237     bool supportsMoz2D;
238     bool canExposeMappedData;
239     bool canConcurrentlyReadLock;
240 
InfoInfo241     Info()
242         : format(gfx::SurfaceFormat::UNKNOWN),
243           hasIntermediateBuffer(false),
244           hasSynchronization(false),
245           supportsMoz2D(false),
246           canExposeMappedData(false),
247           canConcurrentlyReadLock(true) {}
248   };
249 
250   static TextureData* Create(TextureForwarder* aAllocator,
251                              gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
252                              KnowsCompositor* aKnowsCompositor,
253                              BackendSelector aSelector,
254                              TextureFlags aTextureFlags,
255                              TextureAllocationFlags aAllocFlags);
256 
257   static bool IsRemote(KnowsCompositor* aKnowsCompositor,
258                        BackendSelector aSelector);
259 
260   MOZ_COUNTED_DTOR_VIRTUAL(TextureData)
261 
262   virtual void FillInfo(TextureData::Info& aInfo) const = 0;
263 
264   virtual bool Lock(OpenMode aMode) = 0;
265 
266   virtual void Unlock() = 0;
267 
BorrowDrawTarget()268   virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() {
269     return nullptr;
270   }
271 
BorrowSnapshot()272   virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() {
273     return nullptr;
274   }
275 
BorrowMappedData(MappedTextureData &)276   virtual bool BorrowMappedData(MappedTextureData&) { return false; }
277 
BorrowMappedYCbCrData(MappedYCbCrTextureData &)278   virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
279 
280   virtual void Deallocate(LayersIPCChannel* aAllocator) = 0;
281 
282   /// Depending on the texture's flags either Deallocate or Forget is called.
Forget(LayersIPCChannel * aAllocator)283   virtual void Forget(LayersIPCChannel* aAllocator) {}
284 
285   virtual bool Serialize(SurfaceDescriptor& aDescriptor) = 0;
GetSubDescriptor(RemoteDecoderVideoSubDescriptor * aOutDesc)286   virtual void GetSubDescriptor(RemoteDecoderVideoSubDescriptor* aOutDesc) {}
287 
OnForwardedToHost()288   virtual void OnForwardedToHost() {}
289 
290   virtual TextureData* CreateSimilar(
291       LayersIPCChannel* aAllocator, LayersBackend aLayersBackend,
292       TextureFlags aFlags = TextureFlags::DEFAULT,
293       TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const {
294     return nullptr;
295   }
296 
UpdateFromSurface(gfx::SourceSurface * aSurface)297   virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) {
298     return false;
299   };
300 
ReadBack(TextureReadbackSink * aReadbackSink)301   virtual bool ReadBack(TextureReadbackSink* aReadbackSink) { return false; }
302 
SyncWithObject(RefPtr<SyncObjectClient> aSyncObject)303   virtual void SyncWithObject(RefPtr<SyncObjectClient> aSyncObject){};
304 
GetTextureFlags()305   virtual TextureFlags GetTextureFlags() const {
306     return TextureFlags::NO_FLAGS;
307   }
308 
309 #ifdef XP_WIN
AsD3D11TextureData()310   virtual D3D11TextureData* AsD3D11TextureData() { return nullptr; }
AsDXGIYCbCrTextureData()311   virtual DXGIYCbCrTextureData* AsDXGIYCbCrTextureData() { return nullptr; }
312 #endif
313 
AsBufferTextureData()314   virtual BufferTextureData* AsBufferTextureData() { return nullptr; }
315 
AsGPUVideoTextureData()316   virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; }
317 
318   virtual AndroidHardwareBufferTextureData*
AsAndroidHardwareBufferTextureData()319   AsAndroidHardwareBufferTextureData() {
320     return nullptr;
321   }
322 
323   // It is used by AndroidHardwareBufferTextureData and
324   // SharedSurfaceTextureData. Returns buffer id when it owns
325   // AndroidHardwareBuffer. It is used only on android.
GetBufferId()326   virtual Maybe<uint64_t> GetBufferId() const { return Nothing(); }
327 
328   // The acquire fence is a fence that is used for waiting until rendering to
329   // its AHardwareBuffer is completed.
330   // It is used only on android.
GetAcquireFence()331   virtual mozilla::ipc::FileDescriptor GetAcquireFence() {
332     return mozilla::ipc::FileDescriptor();
333   }
334 
335  protected:
336   MOZ_COUNTED_DEFAULT_CTOR(TextureData)
337 };
338 
339 /**
340  * TextureClient is a thin abstraction over texture data that need to be shared
341  * between the content process and the compositor process. It is the
342  * content-side half of a TextureClient/TextureHost pair. A corresponding
343  * TextureHost lives on the compositor-side.
344  *
345  * TextureClient's primary purpose is to present texture data in a way that is
346  * understood by the IPC system. There are two ways to use it:
347  * - Use it to serialize image data that is not IPC-friendly (most likely
348  * involving a copy into shared memory)
349  * - preallocate it and paint directly into it, which avoids copy but requires
350  * the painting code to be aware of TextureClient (or at least the underlying
351  * shared memory).
352  *
353  * There is always one and only one TextureClient per TextureHost, and the
354  * TextureClient/Host pair only owns one buffer of image data through its
355  * lifetime. This means that the lifetime of the underlying shared data
356  * matches the lifetime of the TextureClient/Host pair. It also means
357  * TextureClient/Host do not implement double buffering, which is the
358  * responsibility of the compositable (which would use pairs of Textures).
359  * In order to send several different buffers to the compositor side, use
360  * several TextureClients.
361  */
362 class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
363  public:
364   TextureClient(TextureData* aData, TextureFlags aFlags,
365                 LayersIPCChannel* aAllocator);
366 
367   virtual ~TextureClient();
368 
369   static already_AddRefed<TextureClient> CreateWithData(
370       TextureData* aData, TextureFlags aFlags, LayersIPCChannel* aAllocator);
371 
372   // Creates and allocates a TextureClient usable with Moz2D.
373   static already_AddRefed<TextureClient> CreateForDrawing(
374       KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat,
375       gfx::IntSize aSize, BackendSelector aSelector, TextureFlags aTextureFlags,
376       TextureAllocationFlags flags = ALLOC_DEFAULT);
377 
378   static already_AddRefed<TextureClient> CreateFromSurface(
379       KnowsCompositor* aAllocator, gfx::SourceSurface* aSurface,
380       BackendSelector aSelector, TextureFlags aTextureFlags,
381       TextureAllocationFlags aAllocFlags);
382 
383   // Creates and allocates a TextureClient supporting the YCbCr format.
384   static already_AddRefed<TextureClient> CreateForYCbCr(
385       KnowsCompositor* aAllocator, const gfx::IntRect& aDisplay,
386       const gfx::IntSize& aYSize, uint32_t aYStride,
387       const gfx::IntSize& aCbCrSize, uint32_t aCbCrStride,
388       StereoMode aStereoMode, gfx::ColorDepth aColorDepth,
389       gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange,
390       TextureFlags aTextureFlags);
391 
392   // Creates and allocates a TextureClient (can be accessed through raw
393   // pointers).
394   static already_AddRefed<TextureClient> CreateForRawBufferAccess(
395       KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat,
396       gfx::IntSize aSize, gfx::BackendType aMoz2dBackend,
397       TextureFlags aTextureFlags, TextureAllocationFlags flags = ALLOC_DEFAULT);
398 
399   // Creates and allocates a TextureClient of the same type.
400   already_AddRefed<TextureClient> CreateSimilar(
401       LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
402       TextureFlags aFlags = TextureFlags::DEFAULT,
403       TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const;
404 
405   /**
406    * Locks the shared data, allowing the caller to get access to it.
407    *
408    * Please always lock/unlock when accessing the shared data.
409    * If Lock() returns false, you should not attempt to access the shared data.
410    */
411   bool Lock(OpenMode aMode);
412 
413   void Unlock();
414 
IsLocked()415   bool IsLocked() const { return mIsLocked; }
416 
GetSize()417   gfx::IntSize GetSize() const { return mInfo.size; }
418 
GetFormat()419   gfx::SurfaceFormat GetFormat() const { return mInfo.format; }
420 
421   /**
422    * Returns true if this texture has a synchronization mechanism (mutex, fence,
423    * etc.). Textures that do not implement synchronization should be immutable
424    * or should use immediate uploads (see TextureFlags in CompositorTypes.h)
425    * Even if a texture does not implement synchronization, Lock and Unlock need
426    * to be used appropriately since the latter are also there to map/numap data.
427    */
HasSynchronization()428   bool HasSynchronization() const { return mInfo.hasSynchronization; }
429 
430   /**
431    * Indicates whether the TextureClient implementation is backed by an
432    * in-memory buffer. The consequence of this is that locking the
433    * TextureClient does not contend with locking the texture on the host side.
434    */
HasIntermediateBuffer()435   bool HasIntermediateBuffer() const { return mInfo.hasIntermediateBuffer; }
436 
CanExposeDrawTarget()437   bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; }
438 
CanExposeMappedData()439   bool CanExposeMappedData() const { return mInfo.canExposeMappedData; }
440 
441   /**
442    * Returns a DrawTarget to draw into the TextureClient.
443    * This function should never be called when not on the main thread!
444    *
445    * This must never be called on a TextureClient that is not sucessfully
446    * locked. When called several times within one Lock/Unlock pair, this method
447    * should return the same DrawTarget. The DrawTarget is automatically flushed
448    * by the TextureClient when the latter is unlocked, and the DrawTarget that
449    * will be returned within the next lock/unlock pair may or may not be the
450    * same object. Do not keep references to the DrawTarget outside of the
451    * lock/unlock pair.
452    *
453    * This is typically used as follows:
454    *
455    * if (!texture->Lock(OpenMode::OPEN_READ_WRITE)) {
456    *   return false;
457    * }
458    * {
459    *   // Restrict this code's scope to ensure all references to dt are gone
460    *   // when Unlock is called.
461    *   DrawTarget* dt = texture->BorrowDrawTarget();
462    *   // use the draw target ...
463    * }
464    * texture->Unlock();
465    *
466    */
467   gfx::DrawTarget* BorrowDrawTarget();
468 
469   already_AddRefed<gfx::SourceSurface> BorrowSnapshot();
470 
471   /**
472    * Similar to BorrowDrawTarget but provides direct access to the texture's
473    * bits instead of a DrawTarget.
474    */
475   bool BorrowMappedData(MappedTextureData&);
476   bool BorrowMappedYCbCrData(MappedYCbCrTextureData&);
477 
478   /**
479    * This function can be used to update the contents of the TextureClient
480    * off the main thread.
481    */
482   void UpdateFromSurface(gfx::SourceSurface* aSurface);
483 
484   /**
485    * This method is strictly for debugging. It causes locking and
486    * needless copies.
487    */
488   already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
489 
490   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
491 
492   /**
493    * Copies a rectangle from this texture client to a position in aTarget.
494    * It is assumed that the necessary locks are in place; so this should at
495    * least have a read lock and aTarget should at least have a write lock.
496    */
497   bool CopyToTextureClient(TextureClient* aTarget, const gfx::IntRect* aRect,
498                            const gfx::IntPoint* aPoint);
499 
500   /**
501    * Allocate and deallocate a TextureChild actor.
502    *
503    * TextureChild is an implementation detail of TextureClient that is not
504    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
505    * are for use with the managing IPDL protocols only (so that they can
506    * implement AllocPextureChild and DeallocPTextureChild).
507    */
508   static PTextureChild* CreateIPDLActor();
509   static bool DestroyIPDLActor(PTextureChild* actor);
510 
511   /**
512    * Get the TextureClient corresponding to the actor passed in parameter.
513    */
514   static already_AddRefed<TextureClient> AsTextureClient(PTextureChild* actor);
515 
516   /**
517    * TextureFlags contain important information about various aspects
518    * of the texture, like how its liferime is managed, and how it
519    * should be displayed.
520    * See TextureFlags in CompositorTypes.h.
521    */
GetFlags()522   TextureFlags GetFlags() const { return mFlags; }
523 
HasFlags(TextureFlags aFlags)524   bool HasFlags(TextureFlags aFlags) const {
525     return (mFlags & aFlags) == aFlags;
526   }
527 
528   void AddFlags(TextureFlags aFlags);
529 
530   void RemoveFlags(TextureFlags aFlags);
531 
532   // Must not be called when TextureClient is in use by CompositableClient.
533   void RecycleTexture(TextureFlags aFlags);
534 
535   /**
536    * After being shared with the compositor side, an immutable texture is never
537    * modified, it can only be read. It is safe to not Lock/Unlock immutable
538    * textures.
539    */
IsImmutable()540   bool IsImmutable() const { return !!(mFlags & TextureFlags::IMMUTABLE); }
541 
MarkImmutable()542   void MarkImmutable() { AddFlags(TextureFlags::IMMUTABLE); }
543 
544   bool IsSharedWithCompositor() const;
545 
546   /**
547    * If this method returns false users of TextureClient are not allowed
548    * to access the shared data.
549    */
IsValid()550   bool IsValid() const { return !!mData; }
551 
552   /**
553    * Called when TextureClient is added to CompositableClient.
554    */
555   void SetAddedToCompositableClient();
556 
557   /**
558    * If this method retuns false, TextureClient is already added to
559    * CompositableClient, since its creation or recycling.
560    */
IsAddedToCompositableClient()561   bool IsAddedToCompositableClient() const {
562     return mAddedToCompositableClient;
563   }
564 
565   /**
566    * Create and init the TextureChild/Parent IPDL actor pair
567    * with a CompositableForwarder.
568    *
569    * Should be called only once per TextureClient.
570    * The TextureClient must not be locked when calling this method.
571    */
572   bool InitIPDLActor(CompositableForwarder* aForwarder);
573 
574   /**
575    * Create and init the TextureChild/Parent IPDL actor pair
576    * with a TextureForwarder.
577    *
578    * Should be called only once per TextureClient.
579    * The TextureClient must not be locked when calling this method.
580    */
581   bool InitIPDLActor(KnowsCompositor* aKnowsCompositor);
582 
583   /**
584    * Return a pointer to the IPDLActor.
585    *
586    * This is to be used with IPDL messages only. Do not store the returned
587    * pointer.
588    */
589   PTextureChild* GetIPDLActor();
590 
591   /**
592    * Triggers the destruction of the shared data and the corresponding
593    * TextureHost.
594    *
595    * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the
596    * destruction will be synchronously coordinated with the compositor side,
597    * otherwise it will be done asynchronously.
598    */
599   void Destroy();
600 
601   /**
602    * Track how much of this texture is wasted.
603    * For example we might allocate a 256x256 tile but only use 10x10.
604    */
SetWaste(int aWasteArea)605   void SetWaste(int aWasteArea) {
606     mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
607   }
608 
609   /**
610    * This sets the readback sink that this texture is to use. This will
611    * receive the data for this texture as soon as it becomes available after
612    * texture unlock.
613    */
SetReadbackSink(TextureReadbackSink * aReadbackSink)614   virtual void SetReadbackSink(TextureReadbackSink* aReadbackSink) {
615     mReadbackSink = aReadbackSink;
616   }
617 
SyncWithObject(RefPtr<SyncObjectClient> aSyncObject)618   void SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) {
619     mData->SyncWithObject(aSyncObject);
620   }
621 
GetAllocator()622   LayersIPCChannel* GetAllocator() { return mAllocator; }
623 
GetRecycleAllocator()624   ITextureClientRecycleAllocator* GetRecycleAllocator() {
625     return mRecycleAllocator;
626   }
627   void SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator);
628 
629   /// If you add new code that uses this method, you are probably doing
630   /// something wrong.
GetInternalData()631   TextureData* GetInternalData() { return mData; }
GetInternalData()632   const TextureData* GetInternalData() const { return mData; }
633 
GetSerial()634   uint64_t GetSerial() const { return mSerial; }
635   void GetSurfaceDescriptorRemoteDecoder(
636       SurfaceDescriptorRemoteDecoder* aOutDesc);
637 
638   void CancelWaitForNotifyNotUsed();
639 
640   /**
641    * Set last transaction id of CompositableForwarder.
642    *
643    * Called when TextureClient has TextureFlags::RECYCLE flag.
644    * When CompositableForwarder forwards the TextureClient with
645    * TextureFlags::RECYCLE, it holds TextureClient's ref until host side
646    * releases it. The host side sends TextureClient release message.
647    * The id is used to check if the message is for the last TextureClient
648    * forwarding.
649    */
SetLastFwdTransactionId(uint64_t aTransactionId)650   void SetLastFwdTransactionId(uint64_t aTransactionId) {
651     MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
652     mFwdTransactionId = aTransactionId;
653   }
654 
GetLastFwdTransactionId()655   uint64_t GetLastFwdTransactionId() { return mFwdTransactionId; }
656 
GetReadLock()657   TextureReadLock* GetReadLock() { return mReadLock; }
658 
659   bool IsReadLocked() const;
660 
661   bool TryReadLock();
662   void ReadUnlock();
663 
SetUpdated()664   void SetUpdated() { mUpdated = true; }
665 
666   bool OnForwardedToHost();
667 
668   // Mark that the TextureClient will be used by the paint thread, and should
669   // not free its underlying texture data. This must only be called from the
670   // main thread.
671   void AddPaintThreadRef();
672 
673   // Mark that the TextureClient is no longer in use by the PaintThread. This
674   // must only be called from the PaintThread.
675   void DropPaintThreadRef();
676 
GetExternalImageKey()677   wr::MaybeExternalImageId GetExternalImageKey() { return mExternalImageId; }
678 
679  private:
680   static void TextureClientRecycleCallback(TextureClient* aClient,
681                                            void* aClosure);
682 
683   // Internal helpers for creating texture clients using the actual forwarder
684   // instead of KnowsCompositor. TextureClientPool uses these to let it cache
685   // texture clients per-process instead of per ShadowLayerForwarder, but
686   // everyone else should use the public functions instead.
687   friend class TextureClientPool;
688   static already_AddRefed<TextureClient> CreateForDrawing(
689       TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat,
690       gfx::IntSize aSize, KnowsCompositor* aKnowsCompositor,
691       BackendSelector aSelector, TextureFlags aTextureFlags,
692       TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
693 
694   static already_AddRefed<TextureClient> CreateForRawBufferAccess(
695       LayersIPCChannel* aAllocator, gfx::SurfaceFormat aFormat,
696       gfx::IntSize aSize, gfx::BackendType aMoz2dBackend,
697       LayersBackend aLayersBackend, TextureFlags aTextureFlags,
698       TextureAllocationFlags flags = ALLOC_DEFAULT);
699 
700   void EnableReadLock();
701   void EnableBlockingReadLock();
702 
703   /**
704    * Called once, during the destruction of the Texture, on the thread in which
705    * texture's reference count reaches 0 (could be any thread).
706    *
707    * Here goes the shut-down code that uses virtual methods.
708    * Must only be called by Release().
709    */
Finalize()710   void Finalize() {}
711 
712   friend class AtomicRefCountedWithFinalize<TextureClient>;
713 
714  protected:
715   /**
716    * Should only be called *once* per texture, in TextureClient::InitIPDLActor.
717    * Some texture implementations rely on the fact that the descriptor will be
718    * deserialized.
719    * Calling ToSurfaceDescriptor again after it has already returned true,
720    * or never constructing a TextureHost with aDescriptor may result in a memory
721    * leak (see TextureClientD3D9 for example).
722    */
723   bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor);
724 
725   void LockActor() const;
726   void UnlockActor() const;
727 
728   TextureData::Info mInfo;
729 
730   RefPtr<LayersIPCChannel> mAllocator;
731   RefPtr<TextureChild> mActor;
732   RefPtr<ITextureClientRecycleAllocator> mRecycleAllocator;
733   RefPtr<TextureReadLock> mReadLock;
734 
735   TextureData* mData;
736   RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
737 
738   TextureFlags mFlags;
739 
740   gl::GfxTextureWasteTracker mWasteTracker;
741 
742   OpenMode mOpenMode;
743 #ifdef DEBUG
744   uint32_t mExpectedDtRefs;
745 #endif
746   bool mIsLocked;
747   bool mIsReadLocked;
748   // This member tracks that the texture was written into until the update
749   // is sent to the compositor. We need this remember to lock mReadLock on
750   // behalf of the compositor just before sending the notification.
751   bool mUpdated;
752 
753   // Used when TextureClient is recycled with TextureFlags::RECYCLE flag.
754   bool mAddedToCompositableClient;
755 
756   RefPtr<TextureReadbackSink> mReadbackSink;
757 
758   uint64_t mFwdTransactionId;
759 
760   // Serial id of TextureClient. It is unique in current process.
761   const uint64_t mSerial;
762 
763   // When non-zero, texture data must not be freed.
764   mozilla::Atomic<uintptr_t> mPaintThreadRefs;
765 
766   // External image id. It is unique if it is allocated.
767   // The id is allocated in TextureClient::InitIPDLActor().
768   // Its allocation is supported by
769   // CompositorBridgeChild and ImageBridgeChild for now.
770   wr::MaybeExternalImageId mExternalImageId;
771 
772   // Used to assign serial ids of TextureClient.
773   static mozilla::Atomic<uint64_t> sSerialCounter;
774 
775   friend class TextureChild;
776   friend void TestTextureClientSurface(TextureClient*, gfxImageSurface*);
777   friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&);
778   friend already_AddRefed<TextureHost> CreateTextureHostWithBackend(
779       TextureClient*, ISurfaceAllocator*, LayersBackend&);
780 
781 #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
782  public:
783   // Pointer to the pool this tile came from.
784   TextureClientPool* mPoolTracker;
785 #endif
786 };
787 
788 /**
789  * Task that releases TextureClient pointer on a specified thread.
790  */
791 class TextureClientReleaseTask : public Runnable {
792  public:
TextureClientReleaseTask(TextureClient * aClient)793   explicit TextureClientReleaseTask(TextureClient* aClient)
794       : Runnable("layers::TextureClientReleaseTask"), mTextureClient(aClient) {}
795 
Run()796   NS_IMETHOD Run() override {
797     mTextureClient = nullptr;
798     return NS_OK;
799   }
800 
801  private:
802   RefPtr<TextureClient> mTextureClient;
803 };
804 
805 // Automatically lock and unlock a texture. Since texture locking is fallible,
806 // Succeeded() must be checked on the guard object before proceeding.
807 class MOZ_RAII TextureClientAutoLock {
808  public:
TextureClientAutoLock(TextureClient * aTexture,OpenMode aMode)809   TextureClientAutoLock(TextureClient* aTexture, OpenMode aMode)
810       : mTexture(aTexture), mSucceeded(false) {
811     mSucceeded = mTexture->Lock(aMode);
812 #ifdef DEBUG
813     mChecked = false;
814 #endif
815   }
~TextureClientAutoLock()816   ~TextureClientAutoLock() {
817     MOZ_ASSERT(mChecked);
818     if (mSucceeded) {
819       mTexture->Unlock();
820     }
821   }
822 
Succeeded()823   bool Succeeded() {
824 #ifdef DEBUG
825     mChecked = true;
826 #endif
827     return mSucceeded;
828   }
829 
830  private:
831   TextureClient* mTexture;
832 #ifdef DEBUG
833   bool mChecked;
834 #endif
835   bool mSucceeded;
836 };
837 
838 // Automatically locks and unlocks two texture clients, and exposes them as a
839 // a single draw target dual. Since texture locking is fallible, Succeeded()
840 // must be checked on the guard object before proceeding.
841 class MOZ_RAII DualTextureClientAutoLock {
842  public:
DualTextureClientAutoLock(TextureClient * aTexture,TextureClient * aTextureOnWhite,OpenMode aMode)843   DualTextureClientAutoLock(TextureClient* aTexture,
844                             TextureClient* aTextureOnWhite, OpenMode aMode)
845       : mTarget(nullptr), mTexture(aTexture), mTextureOnWhite(aTextureOnWhite) {
846     if (!mTexture->Lock(aMode)) {
847       return;
848     }
849 
850     mTarget = mTexture->BorrowDrawTarget();
851 
852     if (!mTarget) {
853       mTexture->Unlock();
854       return;
855     }
856 
857     if (!mTextureOnWhite) {
858       return;
859     }
860 
861     if (!mTextureOnWhite->Lock(aMode)) {
862       mTarget = nullptr;
863       mTexture->Unlock();
864       return;
865     }
866 
867     RefPtr<gfx::DrawTarget> targetOnWhite = mTextureOnWhite->BorrowDrawTarget();
868 
869     if (!targetOnWhite) {
870       mTarget = nullptr;
871       mTexture->Unlock();
872       mTextureOnWhite->Unlock();
873       return;
874     }
875 
876     mTarget = gfx::Factory::CreateDualDrawTarget(mTarget, targetOnWhite);
877 
878     if (!mTarget) {
879       mTarget = nullptr;
880       mTexture->Unlock();
881       mTextureOnWhite->Unlock();
882     }
883   }
884 
~DualTextureClientAutoLock()885   ~DualTextureClientAutoLock() {
886     if (Succeeded()) {
887       mTarget = nullptr;
888 
889       mTexture->Unlock();
890       if (mTextureOnWhite) {
891         mTextureOnWhite->Unlock();
892       }
893     }
894   }
895 
Succeeded()896   bool Succeeded() const { return !!mTarget; }
897 
898   operator gfx::DrawTarget*() const { return mTarget; }
899   gfx::DrawTarget* operator->() const { return mTarget; }
900 
901   RefPtr<gfx::DrawTarget> mTarget;
902 
903  private:
904   RefPtr<TextureClient> mTexture;
905   RefPtr<TextureClient> mTextureOnWhite;
906 };
907 
908 class KeepAlive {
909  public:
910   virtual ~KeepAlive() = default;
911 };
912 
913 template <typename T>
914 class TKeepAlive : public KeepAlive {
915  public:
TKeepAlive(T * aData)916   explicit TKeepAlive(T* aData) : mData(aData) {}
917 
918  protected:
919   RefPtr<T> mData;
920 };
921 
922 /// Convenience function to set the content of ycbcr texture.
923 bool UpdateYCbCrTextureClient(TextureClient* aTexture,
924                               const PlanarYCbCrData& aData);
925 
926 TextureType PreferredCanvasTextureType(KnowsCompositor* aKnowsCompositor);
927 
928 }  // namespace layers
929 }  // namespace mozilla
930 
931 #endif
932