Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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
#include "SourceSurfaceSharedData.h"
8
9
#include "mozilla/Likely.h"
10
#include "mozilla/Types.h" // for decltype
11
#include "mozilla/layers/SharedSurfacesChild.h"
12
13
#include "base/process_util.h"
14
15
#ifdef DEBUG
16
/**
17
* If defined, this makes SourceSurfaceSharedData::Finalize memory protect the
18
* underlying shared buffer in the producing process (the content or UI
19
* process). Given flushing the page table is expensive, and its utility is
20
* predominantly diagnostic (in case of overrun), turn it off by default.
21
*/
22
# define SHARED_SURFACE_PROTECT_FINALIZED
23
#endif
24
25
using namespace mozilla::layers;
26
27
namespace mozilla {
28
namespace gfx {
29
30
bool SourceSurfaceSharedDataWrapper::Init(
31
const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
32
const SharedMemoryBasic::Handle& aHandle, base::ProcessId aCreatorPid) {
33
MOZ_ASSERT(!mBuf);
34
mSize = aSize;
35
mStride = aStride;
36
mFormat = aFormat;
37
mCreatorPid = aCreatorPid;
38
39
size_t len = GetAlignedDataLength();
40
mBuf = MakeAndAddRef<SharedMemoryBasic>();
41
if (NS_WARN_IF(
42
!mBuf->SetHandle(aHandle, ipc::SharedMemory::RightsReadOnly)) ||
43
NS_WARN_IF(!mBuf->Map(len))) {
44
mBuf = nullptr;
45
return false;
46
}
47
48
mBuf->CloseHandle();
49
return true;
50
}
51
52
void SourceSurfaceSharedDataWrapper::Init(SourceSurfaceSharedData* aSurface) {
53
MOZ_ASSERT(!mBuf);
54
MOZ_ASSERT(aSurface);
55
mSize = aSurface->mSize;
56
mStride = aSurface->mStride;
57
mFormat = aSurface->mFormat;
58
mCreatorPid = base::GetCurrentProcId();
59
mBuf = aSurface->mBuf;
60
}
61
62
bool SourceSurfaceSharedData::Init(const IntSize& aSize, int32_t aStride,
63
SurfaceFormat aFormat,
64
bool aShare /* = true */) {
65
mSize = aSize;
66
mStride = aStride;
67
mFormat = aFormat;
68
69
size_t len = GetAlignedDataLength();
70
mBuf = new SharedMemoryBasic();
71
if (NS_WARN_IF(!mBuf->Create(len)) || NS_WARN_IF(!mBuf->Map(len))) {
72
mBuf = nullptr;
73
return false;
74
}
75
76
if (aShare) {
77
layers::SharedSurfacesChild::Share(this);
78
}
79
80
return true;
81
}
82
83
void SourceSurfaceSharedData::GuaranteePersistance() {
84
// Shared memory is not unmapped until we release SourceSurfaceSharedData.
85
}
86
87
void SourceSurfaceSharedData::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
88
SizeOfInfo& aInfo) const {
89
MutexAutoLock lock(mMutex);
90
aInfo.AddType(SurfaceType::DATA_SHARED);
91
if (mBuf) {
92
aInfo.mNonHeapBytes = GetAlignedDataLength();
93
}
94
if (!mClosed) {
95
aInfo.mExternalHandles = 1;
96
}
97
Maybe<wr::ExternalImageId> extId = SharedSurfacesChild::GetExternalId(this);
98
if (extId) {
99
aInfo.mExternalId = wr::AsUint64(extId.ref());
100
}
101
}
102
103
uint8_t* SourceSurfaceSharedData::GetDataInternal() const {
104
mMutex.AssertCurrentThreadOwns();
105
106
// If we have an old buffer lingering, it is because we get reallocated to
107
// get a new handle to share, but there were still active mappings.
108
if (MOZ_UNLIKELY(mOldBuf)) {
109
MOZ_ASSERT(mMapCount > 0);
110
MOZ_ASSERT(mFinalized);
111
return static_cast<uint8_t*>(mOldBuf->memory());
112
}
113
return static_cast<uint8_t*>(mBuf->memory());
114
}
115
116
nsresult SourceSurfaceSharedData::ShareToProcess(
117
base::ProcessId aPid, SharedMemoryBasic::Handle& aHandle) {
118
MutexAutoLock lock(mMutex);
119
MOZ_ASSERT(mHandleCount > 0);
120
121
if (mClosed) {
122
return NS_ERROR_NOT_AVAILABLE;
123
}
124
125
bool shared = mBuf->ShareToProcess(aPid, &aHandle);
126
if (MOZ_UNLIKELY(!shared)) {
127
return NS_ERROR_FAILURE;
128
}
129
130
return NS_OK;
131
}
132
133
void SourceSurfaceSharedData::CloseHandleInternal() {
134
mMutex.AssertCurrentThreadOwns();
135
136
if (mClosed) {
137
MOZ_ASSERT(mHandleCount == 0);
138
MOZ_ASSERT(mShared);
139
return;
140
}
141
142
if (mShared) {
143
mBuf->CloseHandle();
144
mClosed = true;
145
}
146
}
147
148
bool SourceSurfaceSharedData::ReallocHandle() {
149
MutexAutoLock lock(mMutex);
150
MOZ_ASSERT(mHandleCount > 0);
151
MOZ_ASSERT(mClosed);
152
153
if (NS_WARN_IF(!mFinalized)) {
154
// We haven't finished populating the surface data yet, which means we are
155
// out of luck, as we have no means of synchronizing with the producer to
156
// write new data to a new buffer. This should be fairly rare, caused by a
157
// crash in the GPU process, while we were decoding an image.
158
return false;
159
}
160
161
size_t len = GetAlignedDataLength();
162
RefPtr<SharedMemoryBasic> buf = new SharedMemoryBasic();
163
if (NS_WARN_IF(!buf->Create(len)) || NS_WARN_IF(!buf->Map(len))) {
164
return false;
165
}
166
167
size_t copyLen = GetDataLength();
168
memcpy(buf->memory(), mBuf->memory(), copyLen);
169
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
170
buf->Protect(static_cast<char*>(buf->memory()), len, RightsRead);
171
#endif
172
173
if (mMapCount > 0 && !mOldBuf) {
174
mOldBuf = std::move(mBuf);
175
}
176
mBuf = std::move(buf);
177
mClosed = false;
178
mShared = false;
179
return true;
180
}
181
182
void SourceSurfaceSharedData::Finalize() {
183
MutexAutoLock lock(mMutex);
184
MOZ_ASSERT(!mFinalized);
185
186
#ifdef SHARED_SURFACE_PROTECT_FINALIZED
187
size_t len = GetAlignedDataLength();
188
mBuf->Protect(static_cast<char*>(mBuf->memory()), len, RightsRead);
189
#endif
190
191
mFinalized = true;
192
}
193
194
} // namespace gfx
195
} // namespace mozilla