Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: sw=2 ts=8 et :
3 : */
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #include "ISurfaceAllocator.h"
9 :
10 : #include "gfxPrefs.h"
11 : #include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
12 : #include "mozilla/layers/TextureHost.h" // for TextureHost
13 : #include "mozilla/layers/TextureForwarder.h"
14 : #include "mozilla/layers/CompositableForwarder.h"
15 :
16 : namespace mozilla {
17 : namespace layers {
18 :
19 39 : NS_IMPL_ISUPPORTS(GfxMemoryImageReporter, nsIMemoryReporter)
20 :
21 : mozilla::Atomic<ptrdiff_t> GfxMemoryImageReporter::sAmount(0);
22 :
23 : /* static */ uint32_t
24 33 : CompositableForwarder::GetMaxFileDescriptorsPerMessage() {
25 : #if defined(OS_POSIX)
26 : static const uint32_t kMaxFileDescriptors = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE;
27 : #else
28 : // default number that works everywhere else
29 : static const uint32_t kMaxFileDescriptors = 250;
30 : #endif
31 33 : return kMaxFileDescriptors;
32 : }
33 :
34 1 : mozilla::ipc::SharedMemory::SharedMemoryType OptimalShmemType()
35 : {
36 1 : return ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
37 : }
38 :
39 : void
40 28 : HostIPCAllocator::SendPendingAsyncMessages()
41 : {
42 28 : if (mPendingAsyncMessage.empty()) {
43 28 : return;
44 : }
45 :
46 : // Some type of AsyncParentMessageData message could have
47 : // one file descriptor (e.g. OpDeliverFence).
48 : // A number of file descriptors per gecko ipc message have a limitation
49 : // on OS_POSIX (MACOSX or LINUX).
50 : #if defined(OS_POSIX)
51 : static const uint32_t kMaxMessageNumber = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE;
52 : #else
53 : // default number that works everywhere else
54 : static const uint32_t kMaxMessageNumber = 250;
55 : #endif
56 :
57 0 : InfallibleTArray<AsyncParentMessageData> messages;
58 0 : messages.SetCapacity(mPendingAsyncMessage.size());
59 0 : for (size_t i = 0; i < mPendingAsyncMessage.size(); i++) {
60 0 : messages.AppendElement(mPendingAsyncMessage[i]);
61 : // Limit maximum number of messages.
62 0 : if (messages.Length() >= kMaxMessageNumber) {
63 0 : SendAsyncMessage(messages);
64 : // Initialize Messages.
65 0 : messages.Clear();
66 : }
67 : }
68 :
69 0 : if (messages.Length() > 0) {
70 0 : SendAsyncMessage(messages);
71 : }
72 0 : mPendingAsyncMessage.clear();
73 : }
74 :
75 : // XXX - We should actually figure out the minimum shmem allocation size on
76 : // a certain platform and use that.
77 : const uint32_t sShmemPageSize = 4096;
78 :
79 : #ifdef DEBUG
80 : const uint32_t sSupportedBlockSize = 4;
81 : #endif
82 :
83 0 : FixedSizeSmallShmemSectionAllocator::FixedSizeSmallShmemSectionAllocator(LayersIPCChannel* aShmProvider)
84 0 : : mShmProvider(aShmProvider)
85 : {
86 0 : MOZ_ASSERT(mShmProvider);
87 0 : }
88 :
89 0 : FixedSizeSmallShmemSectionAllocator::~FixedSizeSmallShmemSectionAllocator()
90 : {
91 0 : ShrinkShmemSectionHeap();
92 0 : }
93 :
94 : bool
95 0 : FixedSizeSmallShmemSectionAllocator::IPCOpen() const
96 : {
97 0 : return mShmProvider->IPCOpen();
98 : }
99 :
100 : bool
101 0 : FixedSizeSmallShmemSectionAllocator::AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection)
102 : {
103 : // For now we only support sizes of 4. If we want to support different sizes
104 : // some more complicated bookkeeping should be added.
105 0 : MOZ_ASSERT(aSize == sSupportedBlockSize);
106 0 : MOZ_ASSERT(aShmemSection);
107 :
108 0 : if (!IPCOpen()) {
109 0 : gfxCriticalError() << "Attempt to allocate a ShmemSection after shutdown.";
110 0 : return false;
111 : }
112 :
113 0 : uint32_t allocationSize = (aSize + sizeof(ShmemSectionHeapAllocation));
114 :
115 0 : for (size_t i = 0; i < mUsedShmems.size(); i++) {
116 0 : ShmemSectionHeapHeader* header = mUsedShmems[i].get<ShmemSectionHeapHeader>();
117 0 : if ((header->mAllocatedBlocks + 1) * allocationSize + sizeof(ShmemSectionHeapHeader) < sShmemPageSize) {
118 0 : aShmemSection->shmem() = mUsedShmems[i];
119 0 : MOZ_ASSERT(mUsedShmems[i].IsWritable());
120 0 : break;
121 : }
122 : }
123 :
124 0 : if (!aShmemSection->shmem().IsWritable()) {
125 0 : ipc::Shmem tmp;
126 0 : if (!mShmProvider->AllocUnsafeShmem(sShmemPageSize, OptimalShmemType(), &tmp)) {
127 0 : return false;
128 : }
129 :
130 0 : ShmemSectionHeapHeader* header = tmp.get<ShmemSectionHeapHeader>();
131 0 : header->mTotalBlocks = 0;
132 0 : header->mAllocatedBlocks = 0;
133 :
134 0 : mUsedShmems.push_back(tmp);
135 0 : aShmemSection->shmem() = tmp;
136 : }
137 :
138 0 : MOZ_ASSERT(aShmemSection->shmem().IsWritable());
139 :
140 0 : ShmemSectionHeapHeader* header = aShmemSection->shmem().get<ShmemSectionHeapHeader>();
141 0 : uint8_t* heap = aShmemSection->shmem().get<uint8_t>() + sizeof(ShmemSectionHeapHeader);
142 :
143 0 : ShmemSectionHeapAllocation* allocHeader = nullptr;
144 :
145 0 : if (header->mTotalBlocks > header->mAllocatedBlocks) {
146 : // Search for the first available block.
147 0 : for (size_t i = 0; i < header->mTotalBlocks; i++) {
148 0 : allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap);
149 :
150 0 : if (allocHeader->mStatus == STATUS_FREED) {
151 0 : break;
152 : }
153 0 : heap += allocationSize;
154 : }
155 0 : MOZ_ASSERT(allocHeader && allocHeader->mStatus == STATUS_FREED);
156 0 : MOZ_ASSERT(allocHeader->mSize == sSupportedBlockSize);
157 : } else {
158 0 : heap += header->mTotalBlocks * allocationSize;
159 :
160 0 : header->mTotalBlocks++;
161 0 : allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap);
162 0 : allocHeader->mSize = aSize;
163 : }
164 :
165 0 : MOZ_ASSERT(allocHeader);
166 0 : header->mAllocatedBlocks++;
167 0 : allocHeader->mStatus = STATUS_ALLOCATED;
168 :
169 0 : aShmemSection->size() = aSize;
170 0 : aShmemSection->offset() = (heap + sizeof(ShmemSectionHeapAllocation)) - aShmemSection->shmem().get<uint8_t>();
171 0 : ShrinkShmemSectionHeap();
172 0 : return true;
173 : }
174 :
175 : void
176 0 : FixedSizeSmallShmemSectionAllocator::FreeShmemSection(mozilla::layers::ShmemSection& aShmemSection)
177 : {
178 0 : MOZ_ASSERT(aShmemSection.size() == sSupportedBlockSize);
179 0 : MOZ_ASSERT(aShmemSection.offset() < sShmemPageSize - sSupportedBlockSize);
180 :
181 0 : if (!aShmemSection.shmem().IsWritable()) {
182 0 : return;
183 : }
184 :
185 : ShmemSectionHeapAllocation* allocHeader =
186 0 : reinterpret_cast<ShmemSectionHeapAllocation*>(aShmemSection.shmem().get<char>() +
187 0 : aShmemSection.offset() -
188 0 : sizeof(ShmemSectionHeapAllocation));
189 :
190 0 : MOZ_ASSERT(allocHeader->mSize == aShmemSection.size());
191 :
192 0 : DebugOnly<bool> success = allocHeader->mStatus.compareExchange(STATUS_ALLOCATED, STATUS_FREED);
193 : // If this fails something really weird is going on.
194 0 : MOZ_ASSERT(success);
195 :
196 0 : ShmemSectionHeapHeader* header = aShmemSection.shmem().get<ShmemSectionHeapHeader>();
197 0 : header->mAllocatedBlocks--;
198 : }
199 :
200 : void
201 0 : FixedSizeSmallShmemSectionAllocator::DeallocShmemSection(mozilla::layers::ShmemSection& aShmemSection)
202 : {
203 0 : if (!IPCOpen()) {
204 0 : gfxCriticalNote << "Attempt to dealloc a ShmemSections after shutdown.";
205 0 : return;
206 : }
207 :
208 0 : FreeShmemSection(aShmemSection);
209 0 : ShrinkShmemSectionHeap();
210 : }
211 :
212 :
213 : void
214 0 : FixedSizeSmallShmemSectionAllocator::ShrinkShmemSectionHeap()
215 : {
216 0 : if (!IPCOpen()) {
217 0 : mUsedShmems.clear();
218 0 : return;
219 : }
220 :
221 : // The loop will terminate as we either increase i, or decrease size
222 : // every time through.
223 0 : size_t i = 0;
224 0 : while (i < mUsedShmems.size()) {
225 0 : ShmemSectionHeapHeader* header = mUsedShmems[i].get<ShmemSectionHeapHeader>();
226 0 : if (header->mAllocatedBlocks == 0) {
227 0 : mShmProvider->DeallocShmem(mUsedShmems[i]);
228 : // We don't particularly care about order, move the last one in the array
229 : // to this position.
230 0 : if (i < mUsedShmems.size() - 1) {
231 0 : mUsedShmems[i] = mUsedShmems[mUsedShmems.size() - 1];
232 : }
233 0 : mUsedShmems.pop_back();
234 : } else {
235 0 : i++;
236 : }
237 : }
238 : }
239 :
240 : } // namespace layers
241 : } // namespace mozilla
|