michael@0: // vim:set ts=4 sts=4 sw=4 et cin: michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_SHARED_MEMORYSURFACE_H michael@0: #define GFX_SHARED_MEMORYSURFACE_H michael@0: michael@0: #include "mozilla/ipc/Shmem.h" michael@0: #include "mozilla/ipc/SharedMemory.h" michael@0: michael@0: #include "gfxASurface.h" michael@0: #include "gfxImageSurface.h" michael@0: #include "pratom.h" michael@0: michael@0: typedef struct _cairo_user_data_key cairo_user_data_key_t; michael@0: michael@0: struct SharedImageInfo { michael@0: int32_t width; michael@0: int32_t height; michael@0: gfxImageFormat format; michael@0: int32_t readCount; michael@0: }; michael@0: michael@0: inline SharedImageInfo* michael@0: GetShmInfoPtr(const mozilla::ipc::Shmem& aShmem) michael@0: { michael@0: return reinterpret_cast michael@0: (aShmem.get() + aShmem.Size() - sizeof(SharedImageInfo)); michael@0: } michael@0: michael@0: extern const cairo_user_data_key_t SHM_KEY; michael@0: michael@0: template michael@0: class gfxBaseSharedMemorySurface : public Base { michael@0: typedef mozilla::ipc::SharedMemory SharedMemory; michael@0: typedef mozilla::ipc::Shmem Shmem; michael@0: friend class gfxReusableSharedImageSurfaceWrapper; michael@0: michael@0: public: michael@0: virtual ~gfxBaseSharedMemorySurface() michael@0: { michael@0: MOZ_COUNT_DTOR(gfxBaseSharedMemorySurface); michael@0: } michael@0: michael@0: /** michael@0: * Return a new gfxSharedImageSurface around a shmem segment newly michael@0: * allocated by this function. |aAllocator| is the object used to michael@0: * allocate the new shmem segment. Null is returned if creating michael@0: * the surface failed. michael@0: * michael@0: * NB: the *caller* is responsible for freeing the Shmem allocated michael@0: * by this function. michael@0: */ michael@0: template michael@0: static already_AddRefed michael@0: Create(ShmemAllocator* aAllocator, michael@0: const gfxIntSize& aSize, michael@0: gfxImageFormat aFormat, michael@0: SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC) michael@0: { michael@0: return Create(aAllocator, aSize, aFormat, aShmType); michael@0: } michael@0: michael@0: /** michael@0: * Return a new gfxSharedImageSurface that wraps a shmem segment michael@0: * already created by the Create() above. Bad things will happen michael@0: * if an attempt is made to wrap any other shmem segment. Null is michael@0: * returned if creating the surface failed. michael@0: */ michael@0: static already_AddRefed michael@0: Open(const Shmem& aShmem) michael@0: { michael@0: SharedImageInfo* shmInfo = GetShmInfoPtr(aShmem); michael@0: gfxIntSize size(shmInfo->width, shmInfo->height); michael@0: if (!gfxASurface::CheckSurfaceSize(size)) michael@0: return nullptr; michael@0: michael@0: gfxImageFormat format = (gfxImageFormat)shmInfo->format; michael@0: long stride = gfxImageSurface::ComputeStride(size, format); michael@0: michael@0: nsRefPtr s = michael@0: new Sub(size, michael@0: stride, michael@0: format, michael@0: aShmem); michael@0: // We didn't create this Shmem and so don't free it on errors michael@0: return (s->CairoStatus() != 0) ? nullptr : s.forget(); michael@0: } michael@0: michael@0: template michael@0: static already_AddRefed michael@0: CreateUnsafe(ShmemAllocator* aAllocator, michael@0: const gfxIntSize& aSize, michael@0: gfxImageFormat aFormat, michael@0: SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC) michael@0: { michael@0: return Create(aAllocator, aSize, aFormat, aShmType); michael@0: } michael@0: michael@0: Shmem& GetShmem() { return mShmem; } michael@0: michael@0: static bool IsSharedImage(gfxASurface *aSurface) michael@0: { michael@0: return (aSurface michael@0: && aSurface->GetType() == gfxSurfaceType::Image michael@0: && aSurface->GetData(&SHM_KEY)); michael@0: } michael@0: michael@0: protected: michael@0: gfxBaseSharedMemorySurface(const gfxIntSize& aSize, long aStride, michael@0: gfxImageFormat aFormat, michael@0: const Shmem& aShmem) michael@0: : Base(aShmem.get(), aSize, aStride, aFormat) michael@0: { michael@0: MOZ_COUNT_CTOR(gfxBaseSharedMemorySurface); michael@0: michael@0: mShmem = aShmem; michael@0: this->SetData(&SHM_KEY, this, nullptr); michael@0: } michael@0: michael@0: private: michael@0: void WriteShmemInfo() michael@0: { michael@0: SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); michael@0: shmInfo->width = this->mSize.width; michael@0: shmInfo->height = this->mSize.height; michael@0: shmInfo->format = this->mFormat; michael@0: shmInfo->readCount = 0; michael@0: } michael@0: michael@0: int32_t michael@0: ReadLock() michael@0: { michael@0: SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); michael@0: return PR_ATOMIC_INCREMENT(&shmInfo->readCount); michael@0: } michael@0: michael@0: int32_t michael@0: ReadUnlock() michael@0: { michael@0: SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); michael@0: return PR_ATOMIC_DECREMENT(&shmInfo->readCount); michael@0: } michael@0: michael@0: int32_t michael@0: GetReadCount() michael@0: { michael@0: SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); michael@0: return shmInfo->readCount; michael@0: } michael@0: michael@0: static size_t GetAlignedSize(const gfxIntSize& aSize, long aStride) michael@0: { michael@0: #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3) michael@0: return MOZ_ALIGN_WORD(sizeof(SharedImageInfo) + aSize.height * aStride); michael@0: } michael@0: michael@0: template michael@0: static already_AddRefed michael@0: Create(ShmemAllocator* aAllocator, michael@0: const gfxIntSize& aSize, michael@0: gfxImageFormat aFormat, michael@0: SharedMemory::SharedMemoryType aShmType) michael@0: { michael@0: if (!gfxASurface::CheckSurfaceSize(aSize)) michael@0: return nullptr; michael@0: michael@0: Shmem shmem; michael@0: long stride = gfxImageSurface::ComputeStride(aSize, aFormat); michael@0: size_t size = GetAlignedSize(aSize, stride); michael@0: if (!Unsafe) { michael@0: if (!aAllocator->AllocShmem(size, aShmType, &shmem)) michael@0: return nullptr; michael@0: } else { michael@0: if (!aAllocator->AllocUnsafeShmem(size, aShmType, &shmem)) michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr s = michael@0: new Sub(aSize, stride, aFormat, shmem); michael@0: if (s->CairoStatus() != 0) { michael@0: aAllocator->DeallocShmem(shmem); michael@0: return nullptr; michael@0: } michael@0: s->WriteShmemInfo(); michael@0: return s.forget(); michael@0: } michael@0: michael@0: Shmem mShmem; michael@0: michael@0: // Calling these is very bad, disallow it michael@0: gfxBaseSharedMemorySurface(const gfxBaseSharedMemorySurface&); michael@0: gfxBaseSharedMemorySurface& operator=(const gfxBaseSharedMemorySurface&); michael@0: }; michael@0: michael@0: #endif /* GFX_SHARED_MEMORYSURFACE_H */