Bug 1568876 - Make copyRule in the ChangesView fission compatible. r=rcaliman
[gecko.git] / gfx / layers / TextureSync.cpp
blobb24ac7101342847a770d938fb89a827d94745ccd
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/. */
7 #include "TextureSync.h"
9 #include <unordered_set>
11 #include "base/process_util.h"
12 #include "chrome/common/mach_ipc_mac.h"
13 #include "mozilla/ipc/SharedMemoryBasic.h"
14 #include "mozilla/layers/CompositorThread.h"
15 #include "mozilla/StaticMonitor.h"
16 #include "mozilla/StaticPtr.h"
18 #ifdef DEBUG
19 # define LOG_ERROR(str, args...) \
20 PR_BEGIN_MACRO \
21 mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ##args); \
22 NS_WARNING(msg.get()); \
23 PR_END_MACRO
24 #else
25 # define LOG_ERROR(str, args...) \
26 do { /* nothing */ \
27 } while (0)
28 #endif
30 namespace mozilla {
32 namespace layers {
34 // Hold raw pointers and trust that TextureSourceProviders will be
35 // unregistered in their destructors - we don't want to keep these
36 // alive, and destroying them from the main thread will be an
37 // error anyway.
38 StaticAutoPtr<nsTArray<TextureSourceProvider*>> gTextureSourceProviders;
40 static std::map<pid_t, std::unordered_set<uint64_t>> gProcessTextureIds;
41 static StaticMonitor gTextureLockMonitor;
43 const int kSendMessageTimeout = 1000;
44 const int kTextureLockTimeout = 32; // We really don't want to wait more than
45 // two frames for a texture to unlock. This
46 // will in any case be very uncommon.
48 struct WaitForTexturesReply {
49 bool success;
52 struct WaitForTexturesRequest {
53 pid_t pid;
56 static std::unordered_set<uint64_t>* GetLockedTextureIdsForProcess(pid_t pid) {
57 gTextureLockMonitor.AssertCurrentThreadOwns();
59 if (gProcessTextureIds.find(pid) == gProcessTextureIds.end()) {
60 gProcessTextureIds[pid] = std::unordered_set<uint64_t>();
63 return &gProcessTextureIds.at(pid);
66 static bool WaitForTextureIdsToUnlock(pid_t pid,
67 const Span<const uint64_t>& textureIds) {
69 StaticMonitorAutoLock lock(gTextureLockMonitor);
70 std::unordered_set<uint64_t>* freedTextureIds =
71 GetLockedTextureIdsForProcess(pid);
73 TimeStamp start = TimeStamp::Now();
74 while (true) {
75 bool allCleared = true;
76 for (uint64_t textureId : textureIds) {
77 if (freedTextureIds->find(textureId) != freedTextureIds->end()) {
78 allCleared = false;
82 if (allCleared) {
83 return true;
86 if (lock.Wait(TimeDuration::FromMilliseconds(kTextureLockTimeout)) ==
87 CVStatus::Timeout) {
88 return false;
91 // In case the monitor gets signaled multiple times, each less than
92 // kTextureLockTimeout. This ensures that the total time we wait is
93 // < 2 * kTextureLockTimeout
94 if ((TimeStamp::Now() - start).ToMilliseconds() >
95 (double)kTextureLockTimeout) {
96 return false;
102 static void CheckTexturesForUnlock() {
103 if (gTextureSourceProviders) {
104 for (auto it = gTextureSourceProviders->begin();
105 it != gTextureSourceProviders->end(); ++it) {
106 (*it)->TryUnlockTextures();
111 void TextureSync::DispatchCheckTexturesForUnlock() {
112 RefPtr<Runnable> task =
113 NS_NewRunnableFunction("CheckTexturesForUnlock", &CheckTexturesForUnlock);
114 CompositorThreadHolder::Loop()->PostTask(task.forget());
117 void TextureSync::HandleWaitForTexturesMessage(MachReceiveMessage* rmsg,
118 ipc::MemoryPorts* ports) {
119 WaitForTexturesRequest* req =
120 reinterpret_cast<WaitForTexturesRequest*>(rmsg->GetData());
121 uint64_t* textureIds = (uint64_t*)(req + 1);
122 uint32_t textureIdsLength =
123 (rmsg->GetDataLength() - sizeof(WaitForTexturesRequest)) /
124 sizeof(uint64_t);
126 bool success = WaitForTextureIdsToUnlock(
127 req->pid, MakeSpan<uint64_t>(textureIds, textureIdsLength));
129 if (!success) {
130 LOG_ERROR("Waiting for textures to unlock failed.\n");
133 MachSendMessage msg(ipc::kReturnWaitForTexturesMsg);
134 WaitForTexturesReply replydata;
135 replydata.success = success;
136 msg.SetData(&replydata, sizeof(WaitForTexturesReply));
137 kern_return_t err = ports->mSender->SendMessage(msg, kSendMessageTimeout);
138 if (KERN_SUCCESS != err) {
139 LOG_ERROR("SendMessage failed 0x%x %s\n", err, mach_error_string(err));
143 void TextureSync::RegisterTextureSourceProvider(
144 TextureSourceProvider* textureSourceProvider) {
145 if (!gTextureSourceProviders) {
146 gTextureSourceProviders = new nsTArray<TextureSourceProvider*>();
148 MOZ_RELEASE_ASSERT(!gTextureSourceProviders->Contains(textureSourceProvider));
149 gTextureSourceProviders->AppendElement(textureSourceProvider);
152 void TextureSync::UnregisterTextureSourceProvider(
153 TextureSourceProvider* textureSourceProvider) {
154 if (gTextureSourceProviders) {
155 MOZ_ASSERT(gTextureSourceProviders->Contains(textureSourceProvider));
156 gTextureSourceProviders->RemoveElement(textureSourceProvider);
157 if (gTextureSourceProviders->Length() == 0) {
158 gTextureSourceProviders = nullptr;
163 void TextureSync::SetTexturesLocked(pid_t pid,
164 const nsTArray<uint64_t>& textureIds) {
165 StaticMonitorAutoLock mal(gTextureLockMonitor);
166 std::unordered_set<uint64_t>* lockedTextureIds =
167 GetLockedTextureIdsForProcess(pid);
168 for (uint64_t textureId : textureIds) {
169 lockedTextureIds->insert(textureId);
173 void TextureSync::SetTexturesUnlocked(pid_t pid,
174 const nsTArray<uint64_t>& textureIds) {
175 bool oneErased = false;
177 StaticMonitorAutoLock mal(gTextureLockMonitor);
178 std::unordered_set<uint64_t>* lockedTextureIds =
179 GetLockedTextureIdsForProcess(pid);
180 for (uint64_t textureId : textureIds) {
181 if (lockedTextureIds->erase(textureId)) {
182 oneErased = true;
186 if (oneErased) {
187 gTextureLockMonitor.NotifyAll();
191 void TextureSync::Shutdown() {
193 StaticMonitorAutoLock lock(gTextureLockMonitor);
195 for (auto& lockedTextureIds : gProcessTextureIds) {
196 lockedTextureIds.second.clear();
200 gTextureLockMonitor.NotifyAll();
203 StaticMonitorAutoLock lock(gTextureLockMonitor);
204 gProcessTextureIds.clear();
208 void TextureSync::UpdateTextureLocks(base::ProcessId aProcessId) {
209 if (aProcessId == base::GetCurrentProcId()) {
210 DispatchCheckTexturesForUnlock();
211 return;
214 MachSendMessage smsg(ipc::kUpdateTextureLocksMsg);
215 smsg.SetData(&aProcessId, sizeof(aProcessId));
216 ipc::SharedMemoryBasic::SendMachMessage(aProcessId, smsg, NULL);
219 bool TextureSync::WaitForTextures(base::ProcessId aProcessId,
220 const nsTArray<uint64_t>& textureIds) {
221 if (aProcessId == base::GetCurrentProcId()) {
222 bool success =
223 WaitForTextureIdsToUnlock(aProcessId, MakeSpan<uint64_t>(textureIds));
224 if (!success) {
225 LOG_ERROR("Failed waiting for textures to unlock.\n");
228 return success;
231 MachSendMessage smsg(ipc::kWaitForTexturesMsg);
232 size_t messageSize =
233 sizeof(WaitForTexturesRequest) + textureIds.Length() * sizeof(uint64_t);
234 UniquePtr<uint8_t[]> messageData = MakeUnique<uint8_t[]>(messageSize);
235 WaitForTexturesRequest* req = (WaitForTexturesRequest*)messageData.get();
236 uint64_t* reqTextureIds = (uint64_t*)(req + 1);
238 for (uint32_t i = 0; i < textureIds.Length(); ++i) {
239 reqTextureIds[i] = textureIds[i];
242 req->pid = base::GetCurrentProcId();
243 bool dataWasSet = smsg.SetData(req, messageSize);
245 if (!dataWasSet) {
246 LOG_ERROR("Data was too large: %zu\n", messageSize);
247 return false;
250 MachReceiveMessage msg;
251 bool success =
252 ipc::SharedMemoryBasic::SendMachMessage(aProcessId, smsg, &msg);
253 if (!success) {
254 return false;
257 if (msg.GetDataLength() != sizeof(WaitForTexturesReply)) {
258 LOG_ERROR("Improperly formatted reply\n");
259 return false;
262 WaitForTexturesReply* msg_data =
263 reinterpret_cast<WaitForTexturesReply*>(msg.GetData());
264 if (!msg_data->success) {
265 LOG_ERROR("Failed waiting for textures to unlock.\n");
266 return false;
269 return true;
272 void TextureSync::CleanupForPid(base::ProcessId aProcessId) {
274 StaticMonitorAutoLock lock(gTextureLockMonitor);
275 std::unordered_set<uint64_t>* lockedTextureIds =
276 GetLockedTextureIdsForProcess(aProcessId);
277 lockedTextureIds->clear();
279 gTextureLockMonitor.NotifyAll();
282 } // namespace layers
284 } // namespace mozilla