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 GFX_LAYERS_ISURFACEDEALLOCATOR
8 #define GFX_LAYERS_ISURFACEDEALLOCATOR
9 
10 #include <stddef.h>  // for size_t
11 #include <stdint.h>  // for uint32_t
12 #include "gfxTypes.h"
13 #include "mozilla/gfx/Point.h"         // for IntSize
14 #include "mozilla/ipc/SharedMemory.h"  // for SharedMemory, etc
15 #include "mozilla/RefPtr.h"
16 #include "nsIMemoryReporter.h"              // for nsIMemoryReporter
17 #include "mozilla/Atomics.h"                // for Atomic
18 #include "mozilla/layers/LayersMessages.h"  // for ShmemSection
19 
20 namespace mozilla {
21 namespace ipc {
22 class Shmem;
23 class IShmemAllocator;
24 }  // namespace ipc
25 namespace gfx {
26 class DataSourceSurface;
27 }  // namespace gfx
28 
29 namespace layers {
30 
31 class CompositableForwarder;
32 class CompositorBridgeParentBase;
33 class TextureForwarder;
34 
35 class ShmemSectionAllocator;
36 class LegacySurfaceDescriptorAllocator;
37 class ClientIPCAllocator;
38 class HostIPCAllocator;
39 class LayersIPCChannel;
40 
41 enum BufferCapabilities {
42   DEFAULT_BUFFER_CAPS = 0,
43   /**
44    * The allocated buffer must be efficiently mappable as a DataSourceSurface.
45    */
46   MAP_AS_IMAGE_SURFACE = 1 << 0,
47   /**
48    * The allocated buffer will be used for GL rendering only
49    */
50   USING_GL_RENDERING_ONLY = 1 << 1
51 };
52 
53 class SurfaceDescriptor;
54 
55 mozilla::ipc::SharedMemory::SharedMemoryType OptimalShmemType();
56 
57 /**
58  * An interface used to create and destroy surfaces that are shared with the
59  * Compositor process (using shmem, or other platform specific memory)
60  *
61  * Most of the methods here correspond to methods that are implemented by IPDL
62  * actors without a common polymorphic interface.
63  * These methods should be only called in the ipdl implementor's thread, unless
64  * specified otherwise in the implementing class.
65  */
66 class ISurfaceAllocator {
67  public:
68   MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
69   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ISurfaceAllocator)
70 
71   ISurfaceAllocator() = default;
72 
73   // down-casting
74 
AsShmemAllocator()75   virtual mozilla::ipc::IShmemAllocator* AsShmemAllocator() { return nullptr; }
76 
AsShmemSectionAllocator()77   virtual ShmemSectionAllocator* AsShmemSectionAllocator() { return nullptr; }
78 
AsCompositableForwarder()79   virtual CompositableForwarder* AsCompositableForwarder() { return nullptr; }
80 
GetTextureForwarder()81   virtual TextureForwarder* GetTextureForwarder() { return nullptr; }
82 
AsClientAllocator()83   virtual ClientIPCAllocator* AsClientAllocator() { return nullptr; }
84 
AsHostIPCAllocator()85   virtual HostIPCAllocator* AsHostIPCAllocator() { return nullptr; }
86 
87   virtual LegacySurfaceDescriptorAllocator*
AsLegacySurfaceDescriptorAllocator()88   AsLegacySurfaceDescriptorAllocator() {
89     return nullptr;
90   }
91 
AsCompositorBridgeParentBase()92   virtual CompositorBridgeParentBase* AsCompositorBridgeParentBase() {
93     return nullptr;
94   }
95 
96   // ipc info
97 
IPCOpen()98   virtual bool IPCOpen() const { return true; }
99 
100   virtual bool IsSameProcess() const = 0;
101 
UsesImageBridge()102   virtual bool UsesImageBridge() const { return false; }
103 
UsesWebRenderBridge()104   virtual bool UsesWebRenderBridge() const { return false; }
105 
106  protected:
Finalize()107   void Finalize() {}
108 
109   virtual ~ISurfaceAllocator() = default;
110 };
111 
112 /// Methods that are specific to the client/child side.
113 class ClientIPCAllocator : public ISurfaceAllocator {
114  public:
115   ClientIPCAllocator() = default;
116 
AsClientAllocator()117   ClientIPCAllocator* AsClientAllocator() override { return this; }
118 
119   virtual base::ProcessId GetParentPid() const = 0;
120 
121   virtual MessageLoop* GetMessageLoop() const = 0;
122 
123   virtual void CancelWaitForNotifyNotUsed(uint64_t aTextureId) = 0;
124 };
125 
126 /// Methods that are specific to the host/parent side.
127 class HostIPCAllocator : public ISurfaceAllocator {
128  public:
129   HostIPCAllocator() = default;
130 
AsHostIPCAllocator()131   HostIPCAllocator* AsHostIPCAllocator() override { return this; }
132 
133   /**
134    * Get child side's process Id.
135    */
136   virtual base::ProcessId GetChildProcessId() = 0;
137 
138   virtual void NotifyNotUsed(PTextureParent* aTexture,
139                              uint64_t aTransactionId) = 0;
140 
141   virtual void SendAsyncMessage(
142       const nsTArray<AsyncParentMessageData>& aMessage) = 0;
143 
144   virtual void SendPendingAsyncMessages();
145 
SetAboutToSendAsyncMessages()146   virtual void SetAboutToSendAsyncMessages() {
147     mAboutToSendAsyncMessages = true;
148   }
149 
IsAboutToSendAsyncMessages()150   bool IsAboutToSendAsyncMessages() { return mAboutToSendAsyncMessages; }
151 
152  protected:
153   std::vector<AsyncParentMessageData> mPendingAsyncMessage;
154   bool mAboutToSendAsyncMessages = false;
155 };
156 
157 /// An allocator that can group allocations in bigger chunks of shared memory.
158 ///
159 /// The allocated shmem sections can only be deallocated by the same allocator
160 /// instance (and only in the child process).
161 class ShmemSectionAllocator {
162  public:
163   virtual bool AllocShmemSection(uint32_t aSize,
164                                  ShmemSection* aShmemSection) = 0;
165 
166   virtual void DeallocShmemSection(ShmemSection& aShmemSection) = 0;
167 
MemoryPressure()168   virtual void MemoryPressure() {}
169 };
170 
171 /// Some old stuff that's still around and used for screenshots.
172 ///
173 /// New code should not need this (see TextureClient).
174 class LegacySurfaceDescriptorAllocator {
175  public:
176   virtual bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
177                                       gfxContentType aContent,
178                                       SurfaceDescriptor* aBuffer) = 0;
179 
180   virtual bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
181                                               gfxContentType aContent,
182                                               uint32_t aCaps,
183                                               SurfaceDescriptor* aBuffer) = 0;
184 
185   virtual void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) = 0;
186 };
187 
188 bool IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface);
189 
190 already_AddRefed<gfx::DataSourceSurface> GetSurfaceForDescriptor(
191     const SurfaceDescriptor& aDescriptor);
192 
193 uint8_t* GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor);
194 
195 void DestroySurfaceDescriptor(mozilla::ipc::IShmemAllocator* aAllocator,
196                               SurfaceDescriptor* aSurface);
197 
198 class GfxMemoryImageReporter final : public nsIMemoryReporter {
199   ~GfxMemoryImageReporter() = default;
200 
201  public:
202   NS_DECL_ISUPPORTS
203 
GfxMemoryImageReporter()204   GfxMemoryImageReporter() {
205 #ifdef DEBUG
206     // There must be only one instance of this class, due to |sAmount|
207     // being static.
208     static bool hasRun = false;
209     MOZ_ASSERT(!hasRun);
210     hasRun = true;
211 #endif
212   }
213 
214   MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)215   MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
216 
217   static void DidAlloc(void* aPointer) {
218     sAmount += MallocSizeOfOnAlloc(aPointer);
219   }
220 
WillFree(void * aPointer)221   static void WillFree(void* aPointer) {
222     sAmount -= MallocSizeOfOnFree(aPointer);
223   }
224 
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)225   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
226                             nsISupports* aData, bool aAnonymize) override {
227     MOZ_COLLECT_REPORT(
228         "explicit/gfx/heap-textures", KIND_HEAP, UNITS_BYTES, sAmount,
229         "Heap memory shared between threads by texture clients and hosts.");
230 
231     return NS_OK;
232   }
233 
234  private:
235   // Typically we use |size_t| in memory reporters, but in the past this
236   // variable has sometimes gone negative due to missing DidAlloc() calls.
237   // Therefore, we use a signed type so that any such negative values show up
238   // as negative in about:memory, rather than as enormous positive numbers.
239   static mozilla::Atomic<ptrdiff_t> sAmount;
240 };
241 
242 /// A simple shmem section allocator that can only allocate small
243 /// fixed size elements (only intended to be used to store tile
244 /// copy-on-write locks for now).
245 class FixedSizeSmallShmemSectionAllocator final : public ShmemSectionAllocator {
246  public:
247   enum AllocationStatus { STATUS_ALLOCATED, STATUS_FREED };
248 
249   struct ShmemSectionHeapHeader {
250     Atomic<uint32_t> mTotalBlocks;
251     Atomic<uint32_t> mAllocatedBlocks;
252   };
253 
254   struct ShmemSectionHeapAllocation {
255     Atomic<uint32_t> mStatus;
256     uint32_t mSize;
257   };
258 
259   explicit FixedSizeSmallShmemSectionAllocator(LayersIPCChannel* aShmProvider);
260 
261   ~FixedSizeSmallShmemSectionAllocator();
262 
263   bool AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection) override;
264 
265   void DeallocShmemSection(ShmemSection& aShmemSection) override;
266 
MemoryPressure()267   void MemoryPressure() override { ShrinkShmemSectionHeap(); }
268 
269   // can be called on the compositor process.
270   static void FreeShmemSection(ShmemSection& aShmemSection);
271 
272   void ShrinkShmemSectionHeap();
273 
274   bool IPCOpen() const;
275 
276  protected:
277   std::vector<mozilla::ipc::Shmem> mUsedShmems;
278   LayersIPCChannel* mShmProvider;
279 };
280 
281 }  // namespace layers
282 }  // namespace mozilla
283 
284 #endif
285