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