1 // vim:set ts=4 sts=4 sw=4 et cin:
2 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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_SHARED_MEMORYSURFACE_H
8 #define GFX_SHARED_MEMORYSURFACE_H
9 
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/ipc/Shmem.h"
12 #include "mozilla/ipc/SharedMemory.h"
13 
14 #include "gfxASurface.h"
15 #include "gfxImageSurface.h"
16 #include "pratom.h"
17 
18 typedef struct _cairo_user_data_key cairo_user_data_key_t;
19 
20 struct SharedImageInfo {
21     int32_t width;
22     int32_t height;
23     gfxImageFormat format;
24     int32_t readCount;
25 };
26 
27 inline SharedImageInfo*
GetShmInfoPtr(const mozilla::ipc::Shmem & aShmem)28 GetShmInfoPtr(const mozilla::ipc::Shmem& aShmem)
29 {
30     return reinterpret_cast<SharedImageInfo*>
31         (aShmem.get<char>() + aShmem.Size<char>() - sizeof(SharedImageInfo));
32 }
33 
34 extern const cairo_user_data_key_t SHM_KEY;
35 
36 template <typename Base, typename Sub>
37 class gfxBaseSharedMemorySurface : public Base {
38     typedef mozilla::ipc::SharedMemory SharedMemory;
39     typedef mozilla::ipc::Shmem Shmem;
40 
41 protected:
~gfxBaseSharedMemorySurface()42     virtual ~gfxBaseSharedMemorySurface()
43     {
44         MOZ_COUNT_DTOR(gfxBaseSharedMemorySurface);
45     }
46 
47 public:
48     /**
49      * Return a new gfxSharedImageSurface around a shmem segment newly
50      * allocated by this function.  |aAllocator| is the object used to
51      * allocate the new shmem segment.  Null is returned if creating
52      * the surface failed.
53      *
54      * NB: the *caller* is responsible for freeing the Shmem allocated
55      * by this function.
56      */
57     template<class ShmemAllocator>
58     static already_AddRefed<Sub>
59     Create(ShmemAllocator* aAllocator,
60            const mozilla::gfx::IntSize& aSize,
61            gfxImageFormat aFormat,
62            SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
63     {
64         return Create<ShmemAllocator, false>(aAllocator, aSize, aFormat, aShmType);
65     }
66 
67     /**
68      * Return a new gfxSharedImageSurface that wraps a shmem segment
69      * already created by the Create() above.  Bad things will happen
70      * if an attempt is made to wrap any other shmem segment.  Null is
71      * returned if creating the surface failed.
72      */
73     static already_AddRefed<Sub>
Open(const Shmem & aShmem)74     Open(const Shmem& aShmem)
75     {
76         SharedImageInfo* shmInfo = GetShmInfoPtr(aShmem);
77         mozilla::gfx::IntSize size(shmInfo->width, shmInfo->height);
78         if (!mozilla::gfx::Factory::CheckSurfaceSize(size))
79             return nullptr;
80 
81         gfxImageFormat format = shmInfo->format;
82         long stride = gfxImageSurface::ComputeStride(size, format);
83 
84         RefPtr<Sub> s =
85             new Sub(size,
86                     stride,
87                     format,
88                     aShmem);
89         // We didn't create this Shmem and so don't free it on errors
90         return (s->CairoStatus() != 0) ? nullptr : s.forget();
91     }
92 
93     template<class ShmemAllocator>
94     static already_AddRefed<Sub>
95     CreateUnsafe(ShmemAllocator* aAllocator,
96                  const mozilla::gfx::IntSize& aSize,
97                  gfxImageFormat aFormat,
98                  SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
99     {
100         return Create<ShmemAllocator, true>(aAllocator, aSize, aFormat, aShmType);
101     }
102 
GetShmem()103     Shmem& GetShmem() { return mShmem; }
104 
IsSharedImage(gfxASurface * aSurface)105     static bool IsSharedImage(gfxASurface *aSurface)
106     {
107         return (aSurface
108                 && aSurface->GetType() == gfxSurfaceType::Image
109                 && aSurface->GetData(&SHM_KEY));
110     }
111 
112 protected:
gfxBaseSharedMemorySurface(const mozilla::gfx::IntSize & aSize,long aStride,gfxImageFormat aFormat,const Shmem & aShmem)113     gfxBaseSharedMemorySurface(const mozilla::gfx::IntSize& aSize, long aStride,
114                                gfxImageFormat aFormat,
115                                const Shmem& aShmem)
116       : Base(aShmem.get<unsigned char>(), aSize, aStride, aFormat)
117     {
118         MOZ_COUNT_CTOR(gfxBaseSharedMemorySurface);
119 
120         mShmem = aShmem;
121         this->SetData(&SHM_KEY, this, nullptr);
122     }
123 
124 private:
WriteShmemInfo()125     void WriteShmemInfo()
126     {
127         SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
128         shmInfo->width = this->mSize.width;
129         shmInfo->height = this->mSize.height;
130         shmInfo->format = this->mFormat;
131         shmInfo->readCount = 0;
132     }
133 
134     int32_t
ReadLock()135     ReadLock()
136     {
137         SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
138         return PR_ATOMIC_INCREMENT(&shmInfo->readCount);
139     }
140 
141     int32_t
ReadUnlock()142     ReadUnlock()
143     {
144         SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
145         return PR_ATOMIC_DECREMENT(&shmInfo->readCount);
146     }
147 
148     int32_t
GetReadCount()149     GetReadCount()
150     {
151         SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
152         return shmInfo->readCount;
153     }
154 
GetAlignedSize(const mozilla::gfx::IntSize & aSize,long aStride)155     static size_t GetAlignedSize(const mozilla::gfx::IntSize& aSize, long aStride)
156     {
157         #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
158         return MOZ_ALIGN_WORD(sizeof(SharedImageInfo) + aSize.height * aStride);
159     }
160 
161     template<class ShmemAllocator, bool Unsafe>
162     static already_AddRefed<Sub>
Create(ShmemAllocator * aAllocator,const mozilla::gfx::IntSize & aSize,gfxImageFormat aFormat,SharedMemory::SharedMemoryType aShmType)163     Create(ShmemAllocator* aAllocator,
164            const mozilla::gfx::IntSize& aSize,
165            gfxImageFormat aFormat,
166            SharedMemory::SharedMemoryType aShmType)
167     {
168         if (!mozilla::gfx::Factory::CheckSurfaceSize(aSize))
169             return nullptr;
170 
171         Shmem shmem;
172         long stride = gfxImageSurface::ComputeStride(aSize, aFormat);
173         size_t size = GetAlignedSize(aSize, stride);
174         if (!Unsafe) {
175             if (!aAllocator->AllocShmem(size, aShmType, &shmem))
176                 return nullptr;
177         } else {
178             if (!aAllocator->AllocUnsafeShmem(size, aShmType, &shmem))
179                 return nullptr;
180         }
181 
182         RefPtr<Sub> s =
183             new Sub(aSize, stride, aFormat, shmem);
184         if (s->CairoStatus() != 0) {
185             aAllocator->DeallocShmem(shmem);
186             return nullptr;
187         }
188         s->WriteShmemInfo();
189         return s.forget();
190     }
191 
192     Shmem mShmem;
193 
194     // Calling these is very bad, disallow it
195     gfxBaseSharedMemorySurface(const gfxBaseSharedMemorySurface&);
196     gfxBaseSharedMemorySurface& operator=(const gfxBaseSharedMemorySurface&);
197 };
198 
199 #endif /* GFX_SHARED_MEMORYSURFACE_H */
200