summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxBaseSharedMemorySurface.h
blob: c9e2ab3278e38203bb16f28ec61e9d0a3a458df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// vim:set ts=4 sts=4 sw=4 et cin:
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef GFX_SHARED_MEMORYSURFACE_H
#define GFX_SHARED_MEMORYSURFACE_H

#include "mozilla/gfx/2D.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/SharedMemory.h"

#include "gfxASurface.h"
#include "gfxImageSurface.h"
#include "pratom.h"

typedef struct _cairo_user_data_key cairo_user_data_key_t;

struct SharedImageInfo {
    int32_t width;
    int32_t height;
    gfxImageFormat format;
    int32_t readCount;
};

inline SharedImageInfo*
GetShmInfoPtr(const mozilla::ipc::Shmem& aShmem)
{
    return reinterpret_cast<SharedImageInfo*>
        (aShmem.get<char>() + aShmem.Size<char>() - sizeof(SharedImageInfo));
}

extern const cairo_user_data_key_t SHM_KEY;

template <typename Base, typename Sub>
class gfxBaseSharedMemorySurface : public Base {
    typedef mozilla::ipc::SharedMemory SharedMemory;
    typedef mozilla::ipc::Shmem Shmem;

protected:
    virtual ~gfxBaseSharedMemorySurface()
    {
        MOZ_COUNT_DTOR(gfxBaseSharedMemorySurface);
    }

public:
    /**
     * Return a new gfxSharedImageSurface around a shmem segment newly
     * allocated by this function.  |aAllocator| is the object used to
     * allocate the new shmem segment.  Null is returned if creating
     * the surface failed.
     *
     * NB: the *caller* is responsible for freeing the Shmem allocated
     * by this function.
     */
    template<class ShmemAllocator>
    static already_AddRefed<Sub>
    Create(ShmemAllocator* aAllocator,
           const mozilla::gfx::IntSize& aSize,
           gfxImageFormat aFormat,
           SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
    {
        return Create<ShmemAllocator, false>(aAllocator, aSize, aFormat, aShmType);
    }

    /**
     * Return a new gfxSharedImageSurface that wraps a shmem segment
     * already created by the Create() above.  Bad things will happen
     * if an attempt is made to wrap any other shmem segment.  Null is
     * returned if creating the surface failed.
     */
    static already_AddRefed<Sub>
    Open(const Shmem& aShmem)
    {
        SharedImageInfo* shmInfo = GetShmInfoPtr(aShmem);
        mozilla::gfx::IntSize size(shmInfo->width, shmInfo->height);
        if (!mozilla::gfx::Factory::CheckSurfaceSize(size))
            return nullptr;

        gfxImageFormat format = shmInfo->format;
        long stride = gfxImageSurface::ComputeStride(size, format);

        RefPtr<Sub> s =
            new Sub(size,
                    stride,
                    format,
                    aShmem);
        // We didn't create this Shmem and so don't free it on errors
        return (s->CairoStatus() != 0) ? nullptr : s.forget();
    }

    template<class ShmemAllocator>
    static already_AddRefed<Sub>
    CreateUnsafe(ShmemAllocator* aAllocator,
                 const mozilla::gfx::IntSize& aSize,
                 gfxImageFormat aFormat,
                 SharedMemory::SharedMemoryType aShmType = SharedMemory::TYPE_BASIC)
    {
        return Create<ShmemAllocator, true>(aAllocator, aSize, aFormat, aShmType);
    }

    Shmem& GetShmem() { return mShmem; }

    static bool IsSharedImage(gfxASurface *aSurface)
    {
        return (aSurface
                && aSurface->GetType() == gfxSurfaceType::Image
                && aSurface->GetData(&SHM_KEY));
    }

protected:
    gfxBaseSharedMemorySurface(const mozilla::gfx::IntSize& aSize, long aStride, 
                               gfxImageFormat aFormat, 
                               const Shmem& aShmem)
      : Base(aShmem.get<unsigned char>(), aSize, aStride, aFormat)
    {
        MOZ_COUNT_CTOR(gfxBaseSharedMemorySurface);

        mShmem = aShmem;
        this->SetData(&SHM_KEY, this, nullptr);
    }

private:
    void WriteShmemInfo()
    {
        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
        shmInfo->width = this->mSize.width;
        shmInfo->height = this->mSize.height;
        shmInfo->format = this->mFormat;
        shmInfo->readCount = 0;
    }

    int32_t
    ReadLock()
    {
        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
        return PR_ATOMIC_INCREMENT(&shmInfo->readCount);
    }

    int32_t
    ReadUnlock()
    {
        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
        return PR_ATOMIC_DECREMENT(&shmInfo->readCount);
    }

    int32_t
    GetReadCount()
    {
        SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem);
        return shmInfo->readCount;
    }

    static size_t GetAlignedSize(const mozilla::gfx::IntSize& aSize, long aStride)
    {
        #define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
        return MOZ_ALIGN_WORD(sizeof(SharedImageInfo) + aSize.height * aStride);
    }

    template<class ShmemAllocator, bool Unsafe>
    static already_AddRefed<Sub>
    Create(ShmemAllocator* aAllocator,
           const mozilla::gfx::IntSize& aSize,
           gfxImageFormat aFormat,
           SharedMemory::SharedMemoryType aShmType)
    {
        if (!mozilla::gfx::Factory::CheckSurfaceSize(aSize))
            return nullptr;

        Shmem shmem;
        long stride = gfxImageSurface::ComputeStride(aSize, aFormat);
        size_t size = GetAlignedSize(aSize, stride);
        if (!Unsafe) {
            if (!aAllocator->AllocShmem(size, aShmType, &shmem))
                return nullptr;
        } else {
            if (!aAllocator->AllocUnsafeShmem(size, aShmType, &shmem))
                return nullptr;
        }

        RefPtr<Sub> s =
            new Sub(aSize, stride, aFormat, shmem);
        if (s->CairoStatus() != 0) {
            aAllocator->DeallocShmem(shmem);
            return nullptr;
        }
        s->WriteShmemInfo();
        return s.forget();
    }

    Shmem mShmem;

    // Calling these is very bad, disallow it
    gfxBaseSharedMemorySurface(const gfxBaseSharedMemorySurface&);
    gfxBaseSharedMemorySurface& operator=(const gfxBaseSharedMemorySurface&);
};

#endif /* GFX_SHARED_MEMORYSURFACE_H */