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